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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d22de5c44faf70d934da05efbd93f17373e8317bbc6304c5674c2f79183d45b2
|
4
|
+
data.tar.gz: 89d022cd00c4e14be9c82fc62045e82db6095e9a16239e29c085a605c0c0cde9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8fb4d70f1bc7c29439b7237e38e79f5661334fd7c8c3457f5ae1bde20b053eb95dccd5d8c5ad3bf3a4f16443375ace9f889822116680b136d154e53ab118411
|
7
|
+
data.tar.gz: fdd5d8bc41b89c5e0a4f3c83580f4f45679cb3bc38ee9539f332f1a26572cf68ffd549b7118787f6068d1247711cafe175cf7389a0aff1532cf6407c96384ba7
|
data/CHANGELOG.markdown
CHANGED
@@ -1,13 +1,25 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
=========
|
3
3
|
|
4
|
+
v0.0.18
|
5
|
+
-------
|
6
|
+
|
7
|
+
* restricted the use of the file.succ() method, and removed timestamp functionality from it. Now it only works if the initial file has an extension (no trailing counter, like file.000001 ). Still fills in
|
8
|
+
|
9
|
+
v0.0.17
|
10
|
+
-------
|
11
|
+
|
12
|
+
* `.without_ext()` now takes an argument, will only strip that extension.
|
13
|
+
* updated `fun_with_testing` dependency, moved FunWith::Files-related stuff from that gem to this one.
|
14
|
+
|
15
|
+
|
4
16
|
v0.0.14
|
5
|
-
|
17
|
+
-------
|
6
18
|
|
7
|
-
|
19
|
+
???
|
8
20
|
|
9
21
|
v0.0.12
|
10
|
-
|
22
|
+
-------
|
11
23
|
|
12
24
|
FilePath.touch() takes same options as FileUtils.touch()
|
13
25
|
FilePath.glob() now takes a block (yields files one at a time)
|
data/Gemfile
CHANGED
@@ -7,12 +7,22 @@ source "http://rubygems.org"
|
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
|
9
9
|
group :development do
|
10
|
-
|
11
|
-
|
12
|
-
# gem "bundler", "~> 1.5"
|
13
|
-
# gem "jeweler", "~> 2.0"
|
14
|
-
# gem "debugger", "~> 1.6"
|
15
|
-
gem "fun_with_testing", "~> 0.0"
|
10
|
+
gem "debug"
|
11
|
+
gem "fun_with_testing", "~> 0.0", ">= 0.0.7"
|
16
12
|
end
|
17
13
|
|
18
|
-
|
14
|
+
|
15
|
+
xdg_version = case RUBY_VERSION
|
16
|
+
when /^2\.7/
|
17
|
+
3
|
18
|
+
when /^3\.0/
|
19
|
+
5
|
20
|
+
when /^3\.2/
|
21
|
+
7
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
gem "xdg", "~> #{xdg_version}"
|
27
|
+
|
28
|
+
|
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
# `fun_with_files`
|
2
|
+
|
3
|
+
|
4
|
+
|
2
5
|
|
3
6
|
FunWith::Files adds a bit of whimsy to your file manipulations, if that's what you're looking for.
|
4
7
|
|
@@ -36,18 +39,17 @@ To the code!
|
|
36
39
|
|
37
40
|
|
38
41
|
|
39
|
-
|
42
|
+
### Linking files ###
|
40
43
|
|
41
44
|
While fwf.symlink and fwf.link are both backed by FileUtils.ln / FileUtils.ln_s, the defaults are somewhat different
|
42
45
|
|
43
46
|
|
44
47
|
|
45
|
-
|
48
|
+
## DirectoryBuilder ##
|
46
49
|
|
47
50
|
DirectoryBuilder is a class for defining and populating a file hierarchy with relative ease. DirectoryBuilder is probably most easily demonstrated by example. Sample code:
|
48
51
|
|
49
|
-
# starts by creating directory. If parent
|
50
|
-
# directories don't exist, they will soon.
|
52
|
+
# starts by creating directory. If parent directories don't exist, they will soon.
|
51
53
|
DirectoryBuilder.create( '~/project' ) do |b|
|
52
54
|
b.dir("images") do # creates subdirectory "images", which gets populated within the block
|
53
55
|
for img in src_dir.entries.select{|img| img.extension == ".png"}
|
@@ -60,7 +62,7 @@ DirectoryBuilder is a class for defining and populating a file hierarchy with re
|
|
60
62
|
|
61
63
|
b.dir("text", "scenes") do # creates ~/project/text/scenes subdir (creating two new directories text/ and text/scene/)
|
62
64
|
b.file( "adventure_time.txt" ) do |f|
|
63
|
-
f << "Fill this in later"
|
65
|
+
f << "Fill this in later" # text is written to the file
|
64
66
|
end
|
65
67
|
|
66
68
|
# calling .file without feeding it a block leaves it open for writing,
|
@@ -106,9 +108,9 @@ DirectoryBuilder is a class for defining and populating a file hierarchy with re
|
|
106
108
|
|
107
109
|
|
108
110
|
|
109
|
-
|
111
|
+
## Contributing to fun_with_files ##
|
110
112
|
|
111
|
-
Boilerplate from
|
113
|
+
Boilerplate from Juwelier, but seems to make sense.
|
112
114
|
|
113
115
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
114
116
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
@@ -118,8 +120,7 @@ Boilerplate from Jeweler, but seems to make sense.
|
|
118
120
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
119
121
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
120
122
|
|
121
|
-
|
123
|
+
## Copyright ##
|
122
124
|
|
123
|
-
Copyright (c)
|
124
|
-
further details.
|
125
|
+
Copyright (c) 2020 Bryce Anderson. See LICENSE.txt for further details.
|
125
126
|
|
data/Rakefile
CHANGED
@@ -14,8 +14,8 @@ end
|
|
14
14
|
|
15
15
|
require 'rake'
|
16
16
|
|
17
|
-
# require '
|
18
|
-
|
17
|
+
# require 'juwelier'
|
18
|
+
Juwelier::Tasks.new do |gem|
|
19
19
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
20
20
|
gem.name = "fun_with_files"
|
21
21
|
gem.homepage = "http://github.com/darthschmoo/fun_with_files"
|
@@ -50,7 +50,7 @@ DESC
|
|
50
50
|
]
|
51
51
|
end
|
52
52
|
|
53
|
-
|
53
|
+
Juwelier::RubygemsDotOrgTasks.new
|
54
54
|
|
55
55
|
require 'rake/testtask'
|
56
56
|
Rake::TestTask.new(:test) do |test|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.18
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Files
|
3
|
+
class Bootstrapper
|
4
|
+
def self.bootstrap
|
5
|
+
self.new.bootstrap
|
6
|
+
end
|
7
|
+
|
8
|
+
def bootstrap
|
9
|
+
load_core_extensions
|
10
|
+
install_minimal_requir_functionality
|
11
|
+
run_requir
|
12
|
+
rootify
|
13
|
+
add_filepath_class_methods
|
14
|
+
extend_gem_api
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
# gets all the core-extending modules from fun_with/files/core_extensions and uses them to
|
19
|
+
# beef up the core classes
|
20
|
+
def load_core_extensions
|
21
|
+
for file in Dir.glob( File.join( __dir__, "core_extensions", "*.rb" ) )
|
22
|
+
# remove trailing extension to make it require-friendly.
|
23
|
+
file = file.gsub(/\.rb$/,'')
|
24
|
+
|
25
|
+
require_relative file
|
26
|
+
|
27
|
+
# convert filename into class name
|
28
|
+
target_class_str = filename_to_class_name( file )
|
29
|
+
|
30
|
+
# get the core class that needs extending, and the
|
31
|
+
target_class = Kernel.const_get( target_class_str )
|
32
|
+
mixin_class = Kernel.const_get( "FunWith::Files::CoreExtensions::#{target_class_str}" )
|
33
|
+
|
34
|
+
target_class.send( :include, mixin_class )
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def install_minimal_requir_functionality
|
39
|
+
for fil in %w( file_path
|
40
|
+
string_behavior
|
41
|
+
file_manipulation_methods
|
42
|
+
file_permission_methods
|
43
|
+
digest_methods
|
44
|
+
file_requirements
|
45
|
+
requirements/manager
|
46
|
+
stat_methods )
|
47
|
+
require_relative fil
|
48
|
+
end
|
49
|
+
|
50
|
+
# These have some FilePath methods required by .requir()
|
51
|
+
for mod in [ FunWith::Files::StringBehavior,
|
52
|
+
FunWith::Files::FileManipulationMethods,
|
53
|
+
FunWith::Files::FilePermissionMethods,
|
54
|
+
FunWith::Files::DigestMethods,
|
55
|
+
FunWith::Files::FileRequirements,
|
56
|
+
FunWith::Files::StatMethods ]
|
57
|
+
FunWith::Files::FilePath.send( :include, mod )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def run_requir
|
62
|
+
lib_dir = __dir__.fwf_filepath.up
|
63
|
+
|
64
|
+
# And requir() everything else
|
65
|
+
lib_dir.requir
|
66
|
+
end
|
67
|
+
|
68
|
+
def rootify
|
69
|
+
root_dir = __dir__.fwf_filepath.up.up.up
|
70
|
+
FunWith::Files::RootPath.rootify( FunWith::Files, root_dir )
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_filepath_class_methods
|
74
|
+
FunWith::Files::FilePath.extend( FunWith::Files::FilePathClassMethods )
|
75
|
+
end
|
76
|
+
|
77
|
+
def extend_gem_api
|
78
|
+
FunWith::Files.extend( FunWith::Files::GemAPI )
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def filename_to_class_name( str )
|
83
|
+
File.basename( str ).split( "_" ).map(&:capitalize).join("")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,5 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module FunWith
|
2
|
+
module Files
|
3
|
+
module CoreExtensions
|
4
|
+
module File
|
5
|
+
def fwf_filepath( *args )
|
6
|
+
FunWith::Files::FilePath.new( self.path, *args )
|
7
|
+
end
|
8
|
+
|
9
|
+
# I'm not sure this is the most intuitive meaning, but it seems better than
|
10
|
+
# delegating to Object.
|
11
|
+
def fwf_blank?
|
12
|
+
! self.fwf_filepath.exist?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
4
16
|
end
|
5
17
|
end
|
@@ -1,37 +1,70 @@
|
|
1
1
|
module FunWith
|
2
2
|
module Files
|
3
|
+
DIGEST_METHODS = [:md5, :sha1, :sha2, :sha224, :sha256, :sha384, :sha512]
|
4
|
+
|
3
5
|
module DigestMethods
|
4
|
-
def md5
|
5
|
-
digest( Digest::MD5 )
|
6
|
+
def md5( bytes = :all, offset = 0 )
|
7
|
+
digest( Digest::MD5, bytes, offset )
|
6
8
|
end
|
7
9
|
|
8
|
-
def sha1
|
9
|
-
digest( Digest::SHA1 )
|
10
|
+
def sha1( bytes = :all, offset = 0 )
|
11
|
+
digest( Digest::SHA1, bytes, offset )
|
10
12
|
end
|
11
13
|
|
12
|
-
def sha2
|
13
|
-
digest( Digest::SHA2 )
|
14
|
+
def sha2( bytes = :all, offset = 0 )
|
15
|
+
digest( Digest::SHA2, bytes, offset )
|
14
16
|
end
|
15
17
|
|
16
|
-
def sha224
|
17
|
-
digest( Digest::SHA224 )
|
18
|
+
def sha224( bytes = :all, offset = 0 )
|
19
|
+
digest( Digest::SHA224, bytes, offset )
|
18
20
|
end
|
19
21
|
|
20
|
-
def sha256
|
21
|
-
digest( Digest::SHA256 )
|
22
|
+
def sha256( bytes = :all, offset = 0 )
|
23
|
+
digest( Digest::SHA256, bytes, offset )
|
22
24
|
end
|
23
25
|
|
24
|
-
def sha384
|
25
|
-
digest( Digest::SHA384 )
|
26
|
+
def sha384( bytes = :all, offset = 0 )
|
27
|
+
digest( Digest::SHA384, bytes, offset )
|
26
28
|
end
|
27
29
|
|
28
|
-
def sha512
|
29
|
-
digest( Digest::SHA512 )
|
30
|
+
def sha512( bytes = :all, offset = 0 )
|
31
|
+
digest( Digest::SHA512, bytes, offset )
|
30
32
|
end
|
31
|
-
|
32
|
-
def digest( digest_class = Digest::MD5 )
|
33
|
-
self.file?
|
33
|
+
|
34
|
+
def digest( digest_class = Digest::MD5, bytes = :all, offset = 0 )
|
35
|
+
if self.file? && self.readable?
|
36
|
+
if bytes == :all
|
37
|
+
digest_class.hexdigest( self.read )
|
38
|
+
elsif bytes.is_a?( Integer )
|
39
|
+
digest_class.hexdigest( self.read( bytes, offset ) )
|
40
|
+
else
|
41
|
+
raise ArgumentError.new( "FunWith::Files::DigestMethods.digest() error: bytes argument must be an integer or :all")
|
42
|
+
end
|
43
|
+
else
|
44
|
+
raise IOError.new( "Not a file: #{self.path}" ) unless self.file?
|
45
|
+
raise IOError.new( "Not readable: #{self.path}" ) unless self.readable?
|
46
|
+
end
|
34
47
|
end
|
48
|
+
|
49
|
+
# Takes any of the above-named digest functions, determines
|
50
|
+
# whether the file matches a given digest string.
|
51
|
+
#
|
52
|
+
# Multiple digests can be given simultaneously. All must pass.
|
53
|
+
#
|
54
|
+
# TODO: how to get around the :md6 problem? That is, where the
|
55
|
+
# user is sending the wrong key, and hence not getting false back
|
56
|
+
def valid_digest?( opts )
|
57
|
+
digest_opts = Utils::Opts.narrow_options( opts, DIGEST_METHODS )
|
58
|
+
|
59
|
+
|
60
|
+
for method, digest in opts
|
61
|
+
if DIGEST_METHODS.include?( method )
|
62
|
+
return false unless self.send( method ) == digest
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
return true
|
67
|
+
end
|
35
68
|
end
|
36
69
|
end
|
37
70
|
end
|
@@ -9,6 +9,7 @@ module FunWith
|
|
9
9
|
def initialize( path )
|
10
10
|
@paths = []
|
11
11
|
@current_path = path.fwf_filepath
|
12
|
+
@current_file = nil
|
12
13
|
make_path
|
13
14
|
end
|
14
15
|
|
@@ -40,6 +41,9 @@ module FunWith
|
|
40
41
|
|
41
42
|
# Copies the given source file into a file in the current_path.
|
42
43
|
# If a dest_name is given, the new file will be given that name.
|
44
|
+
#
|
45
|
+
# TODO: Improve testing, explain behavior better, need a way to distinguish between
|
46
|
+
# forceful and gentle copying
|
43
47
|
def copy( src_filepath, dst_name = nil )
|
44
48
|
dst_filepath = dst_name ? @current_path.join( dst_name ) : @current_path
|
45
49
|
FileUtils.copy( src_filepath, dst_filepath )
|
@@ -79,7 +83,7 @@ module FunWith
|
|
79
83
|
# end
|
80
84
|
|
81
85
|
# if file not given, the result is appended to the current file.
|
82
|
-
def download( url, file = nil )
|
86
|
+
def download( url, file = nil, opts = {} )
|
83
87
|
if file
|
84
88
|
if file.fwf_filepath.relative?
|
85
89
|
file = FunWith::Files::FilePath.new( @current_path, file )
|
@@ -89,12 +93,13 @@ module FunWith
|
|
89
93
|
download_to_target( url, f )
|
90
94
|
end
|
91
95
|
elsif @current_file
|
92
|
-
download_to_target( url, @current_file )
|
96
|
+
download_to_target( url, @current_file, opts )
|
93
97
|
else
|
94
98
|
puts "No current file to append #{url} to."
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
102
|
+
# The actual method is installed by 'fun_with_templates'
|
98
103
|
def template( *args )
|
99
104
|
raise "DirectoryBuilder cannot use template() function. require 'fun_with_templates' to enable."
|
100
105
|
end
|
@@ -132,8 +137,8 @@ module FunWith
|
|
132
137
|
@current_file = nil
|
133
138
|
end
|
134
139
|
|
135
|
-
def download_to_target( url, file )
|
136
|
-
Downloader.new.download( url, file )
|
140
|
+
def download_to_target( url, file, signatures = {} )
|
141
|
+
Downloader.new.download( url, file, signatures )
|
137
142
|
end
|
138
143
|
end
|
139
144
|
end
|
@@ -1,36 +1,49 @@
|
|
1
1
|
require 'open-uri' # needed by Utils::Downloader
|
2
2
|
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
require 'openssl'
|
3
5
|
require 'timeout'
|
4
6
|
|
5
7
|
|
6
8
|
module FunWith
|
7
9
|
module Files
|
8
10
|
class Downloader
|
11
|
+
def self.download( *args )
|
12
|
+
self.new.download( *args )
|
13
|
+
end
|
14
|
+
|
9
15
|
# stolen from:
|
10
16
|
# http://stackoverflow.com/questions/2263540/how-do-i-download-a-binary-file-over-http-using-ruby
|
11
|
-
|
17
|
+
|
18
|
+
# options:
|
19
|
+
# :md5 => <digest> : Running md5 on the downloaded file should result in an error
|
20
|
+
# :sha256 => <digest> :
|
21
|
+
def download( url, io, opts = {} )
|
12
22
|
@uri = URI.parse( url )
|
13
23
|
@io = io
|
14
24
|
|
15
|
-
open( url ) do |f|
|
25
|
+
URI.open( url ) do |f|
|
16
26
|
@io << f.read
|
17
27
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
|
29
|
+
io_path = @io.fwf_filepath
|
30
|
+
|
31
|
+
if io_path.file?
|
32
|
+
if io_path.valid_digest?( opts )
|
33
|
+
true
|
34
|
+
else
|
35
|
+
warn( "File may not have downloaded correctly, or is validating against a bad hash #{io_path} #{opts.inspect}")
|
36
|
+
false
|
37
|
+
|
38
|
+
end
|
39
|
+
else
|
40
|
+
warn( "File did not download correctly, or was deleted: #{io_path}")
|
41
|
+
false
|
42
|
+
end
|
43
|
+
rescue StandardError => e
|
32
44
|
handle_network_errors( e )
|
33
45
|
end
|
46
|
+
|
34
47
|
|
35
48
|
def handle_network_errors( e )
|
36
49
|
raise e
|
@@ -1,5 +1,13 @@
|
|
1
1
|
module FunWith
|
2
2
|
module Files
|
3
|
-
|
3
|
+
# Useful... why, exactly?
|
4
|
+
module Errors
|
5
|
+
class Error < StandardError; end
|
6
|
+
class SuccessionFormattingError < Error; end
|
7
|
+
class TimestampFormatUnrecognized < Error; end
|
8
|
+
class FileNotEmpty < Error; end
|
9
|
+
class NotADirectory < Error; end
|
10
|
+
class NotAFile < Error; end
|
11
|
+
end
|
4
12
|
end
|
5
13
|
end
|
@@ -15,6 +15,12 @@ module FunWith
|
|
15
15
|
# ln_s(list, destdir, options)
|
16
16
|
# ln_sf(src, dest, options)
|
17
17
|
|
18
|
+
#
|
19
|
+
|
20
|
+
|
21
|
+
# => [:alias_method, :ancestors, :attr, :attr_accessor, :attr_reader, :attr_writer, :autoload, :autoload?, :cd, :chdir, :chmod, :chmod_R, :chown, :chown_R, :class_eval, :class_exec, :class_variable_defined?, :class_variable_get, :class_variable_set, :class_variables, :cmp, :collect_method, :commands, :compare_file, :compare_stream, :const_defined?, :const_get, :const_missing, :const_set, :constants, :copy, :copy_entry, :copy_file, :copy_stream, :cp, :cp_r, :define_method, :deprecate_constant, :getwd, :have_option?, :identical?, :include, :include?, :included_modules, :install, :instance_method, :instance_methods, :link, :ln, :ln_s, :ln_sf, :makedirs, :method_defined?, :mkdir, :mkdir_p, :mkpath, :module_eval, :module_exec, :move, :mv, :name, :options, :options_of, :prepend, :private_class_method, :private_constant, :private_instance_methods, :private_method_defined?, :private_module_function, :protected_instance_methods, :protected_method_defined?, :public_class_method, :public_constant, :public_instance_method, :public_instance_methods, :public_method_defined?, :pwd, :remove, :remove_class_variable, :remove_dir, :remove_entry, :remove_entry_secure, :remove_file, :remove_method, :rm, :rm_f, :rm_r, :rm_rf, :rmdir, :rmtree, :safe_unlink, :singleton_class?, :symlink, :touch, :undef_method, :uptodate?]
|
22
|
+
|
23
|
+
|
18
24
|
# opts are the last argument, and are passed to FileUtils.cp_r
|
19
25
|
# returns the destination path.
|
20
26
|
# How to detect failure? What to return on failure?
|
@@ -22,16 +28,22 @@ module FunWith
|
|
22
28
|
#
|
23
29
|
def cp( *args )
|
24
30
|
destination_and_options( args ) do |dest, opts|
|
25
|
-
FileUtils.cp_r( self, dest,
|
31
|
+
FileUtils.cp_r( self, dest, ** Utils::Opts.narrow_file_utils_options( opts, :cp_r ) )
|
26
32
|
dest.fwf_filepath
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
30
36
|
alias :copy :cp
|
31
37
|
|
32
|
-
# Treat as a copy then a delete? Nah, that's a lot slower
|
33
|
-
|
34
|
-
|
38
|
+
# Treat as a copy then a delete? Nah, that's a lot slower especially for larger files. Should be much more in tune with what the command line program does.
|
39
|
+
# Treat it as syntactic sugar for FileUtils.mv?
|
40
|
+
# Also want to update the path to the new location - not implemented yet
|
41
|
+
#
|
42
|
+
#
|
43
|
+
def mv( dst, options = {} )
|
44
|
+
# what does FileUtils.rm actually return? Glancing an the source, it
|
45
|
+
# seems to only throw errors.
|
46
|
+
FileUtils.mv( self, dst, **options )
|
35
47
|
end
|
36
48
|
|
37
49
|
alias :move :mv
|
@@ -45,13 +57,11 @@ module FunWith
|
|
45
57
|
def link *args
|
46
58
|
self.destination_and_options( args ) do |lnk, opts|
|
47
59
|
symlink_requested = self.directory? || opts[:symbolic] || opts[:sym] || opts[:soft]
|
48
|
-
|
60
|
+
|
49
61
|
if symlink_requested
|
50
62
|
self.symlink lnk, opts
|
51
63
|
else
|
52
|
-
|
53
|
-
|
54
|
-
FileUtils.ln self, lnk, opts
|
64
|
+
FileUtils.ln self, lnk, ** Utils::Opts.narrow_file_utils_options( opts, :ln )
|
55
65
|
end
|
56
66
|
|
57
67
|
lnk.fwf_filepath
|
@@ -78,7 +88,7 @@ module FunWith
|
|
78
88
|
lnk = lnk.fwf_filepath
|
79
89
|
end
|
80
90
|
|
81
|
-
FileUtils.ln_s( self, lnk,
|
91
|
+
FileUtils.ln_s( self, lnk, ** Utils::Opts.narrow_file_utils_options( opts, :ln_s ) )
|
82
92
|
lnk.fwf_filepath
|
83
93
|
end
|
84
94
|
|
@@ -86,7 +96,7 @@ module FunWith
|
|
86
96
|
|
87
97
|
|
88
98
|
def file_gsub( *args, &block )
|
89
|
-
|
99
|
+
must_be_file
|
90
100
|
|
91
101
|
lines = []
|
92
102
|
self.each_line do |line|
|
@@ -97,8 +107,8 @@ module FunWith
|
|
97
107
|
end
|
98
108
|
|
99
109
|
def file_gsub!( *args, &block )
|
100
|
-
|
101
|
-
|
110
|
+
must_be_file # raises error
|
111
|
+
must_be_writable # raises error
|
102
112
|
|
103
113
|
self.write( self.file_gsub( *args, &block ) )
|
104
114
|
end
|
@@ -113,9 +123,9 @@ module FunWith
|
|
113
123
|
|
114
124
|
# TODO: If it's truncated to a longer length than the original file,
|
115
125
|
# pad with zeros? That's how the UNIX truncate command works.
|
116
|
-
def truncate( len )
|
117
|
-
|
118
|
-
|
126
|
+
def truncate( len = 0 )
|
127
|
+
must_be_file # raises error
|
128
|
+
must_be_writable # raises error
|
119
129
|
|
120
130
|
old_size = self.size
|
121
131
|
padding = len > old_size ? "\0" * (len - old_size) : ""
|