adamwiggins-rush 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +87 -0
- data/Rakefile +61 -0
- data/VERSION +1 -0
- data/bin/rush +13 -0
- data/bin/rushd +7 -0
- data/lib/rush/access.rb +130 -0
- data/lib/rush/array_ext.rb +19 -0
- data/lib/rush/box.rb +112 -0
- data/lib/rush/commands.rb +55 -0
- data/lib/rush/config.rb +154 -0
- data/lib/rush/dir.rb +160 -0
- data/lib/rush/embeddable_shell.rb +26 -0
- data/lib/rush/entry.rb +185 -0
- data/lib/rush/exceptions.rb +31 -0
- data/lib/rush/file.rb +85 -0
- data/lib/rush/find_by.rb +39 -0
- data/lib/rush/fixnum_ext.rb +18 -0
- data/lib/rush/head_tail.rb +11 -0
- data/lib/rush/local.rb +402 -0
- data/lib/rush/process.rb +59 -0
- data/lib/rush/process_set.rb +62 -0
- data/lib/rush/remote.rb +156 -0
- data/lib/rush/search_results.rb +58 -0
- data/lib/rush/server.rb +117 -0
- data/lib/rush/shell.rb +187 -0
- data/lib/rush/ssh_tunnel.rb +122 -0
- data/lib/rush/string_ext.rb +3 -0
- data/lib/rush.rb +87 -0
- data/spec/access_spec.rb +134 -0
- data/spec/array_ext_spec.rb +15 -0
- data/spec/base.rb +24 -0
- data/spec/box_spec.rb +64 -0
- data/spec/commands_spec.rb +47 -0
- data/spec/config_spec.rb +108 -0
- data/spec/dir_spec.rb +164 -0
- data/spec/embeddable_shell_spec.rb +17 -0
- data/spec/entry_spec.rb +133 -0
- data/spec/file_spec.rb +83 -0
- data/spec/find_by_spec.rb +58 -0
- data/spec/fixnum_ext_spec.rb +19 -0
- data/spec/local_spec.rb +352 -0
- data/spec/process_set_spec.rb +50 -0
- data/spec/process_spec.rb +73 -0
- data/spec/remote_spec.rb +140 -0
- data/spec/rush_spec.rb +28 -0
- data/spec/search_results_spec.rb +44 -0
- data/spec/shell_spec.rb +23 -0
- data/spec/ssh_tunnel_spec.rb +122 -0
- data/spec/string_ext_spec.rb +23 -0
- metadata +141 -0
data/lib/rush/dir.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# A dir is a subclass of Rush::Entry that contains other entries. Also known
|
2
|
+
# as a directory or a folder.
|
3
|
+
#
|
4
|
+
# Dirs can be operated on with Rush::Commands the same as an array of files.
|
5
|
+
# They also offer a square bracket accessor which can use globbing to get a
|
6
|
+
# list of files.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# dir = box['/home/adam/']
|
11
|
+
# dir['**/*.rb'].line_count
|
12
|
+
#
|
13
|
+
# In the interactive shell, dir.ls is a useful command.
|
14
|
+
class Rush::Dir < Rush::Entry
|
15
|
+
def dir?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def full_path
|
20
|
+
"#{super}/"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Entries contained within this dir - not recursive.
|
24
|
+
def contents
|
25
|
+
find_by_glob('*')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Files contained in this dir only.
|
29
|
+
def files
|
30
|
+
contents.select { |entry| !entry.dir? }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Other dirs contained in this dir only.
|
34
|
+
def dirs
|
35
|
+
contents.select { |entry| entry.dir? }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Access subentries with square brackets, e.g. dir['subdir/file']
|
39
|
+
def [](key)
|
40
|
+
key = key.to_s
|
41
|
+
if key == '**'
|
42
|
+
files_flattened
|
43
|
+
elsif key.match(/\*/)
|
44
|
+
find_by_glob(key)
|
45
|
+
else
|
46
|
+
find_by_name(key)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# Slashes work as well, e.g. dir/'subdir/file'
|
50
|
+
alias_method :/, :[]
|
51
|
+
|
52
|
+
def find_by_name(name) # :nodoc:
|
53
|
+
Rush::Entry.factory("#{full_path}/#{name}", box)
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_by_glob(glob) # :nodoc:
|
57
|
+
connection.index(full_path, glob).map do |fname|
|
58
|
+
Rush::Entry.factory("#{full_path}/#{fname}", box)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# A list of all the recursively contained entries in flat form.
|
63
|
+
def entries_tree
|
64
|
+
find_by_glob('**/*')
|
65
|
+
end
|
66
|
+
|
67
|
+
# Recursively contained files.
|
68
|
+
def files_flattened
|
69
|
+
entries_tree.select { |e| !e.dir? }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Recursively contained dirs.
|
73
|
+
def dirs_flattened
|
74
|
+
entries_tree.select { |e| e.dir? }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Given a list of flat filenames, product a list of entries under this dir.
|
78
|
+
# Mostly for internal use.
|
79
|
+
def make_entries(filenames)
|
80
|
+
filenames.map do |fname|
|
81
|
+
Rush::Entry.factory("#{full_path}/#{fname}")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Create a blank file within this dir.
|
86
|
+
def create_file(name)
|
87
|
+
file = self[name].create
|
88
|
+
file.write('')
|
89
|
+
file
|
90
|
+
end
|
91
|
+
|
92
|
+
# Create an empty subdir within this dir.
|
93
|
+
def create_dir(name)
|
94
|
+
name += '/' unless name.tail(1) == '/'
|
95
|
+
self[name].create
|
96
|
+
end
|
97
|
+
|
98
|
+
# Create an instantiated but not yet filesystem-created dir.
|
99
|
+
def create
|
100
|
+
connection.create_dir(full_path)
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
# Get the total disk usage of the dir and all its contents.
|
105
|
+
def size
|
106
|
+
connection.size(full_path)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Contained dirs that are not hidden.
|
110
|
+
def nonhidden_dirs
|
111
|
+
dirs.select do |dir|
|
112
|
+
!dir.hidden?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Contained files that are not hidden.
|
117
|
+
def nonhidden_files
|
118
|
+
files.select do |file|
|
119
|
+
!file.hidden?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Run a bash command starting in this directory. Options are the same as Rush::Box#bash.
|
124
|
+
def bash(command, options={})
|
125
|
+
box.bash "cd #{quoted_path} && #{command}", options
|
126
|
+
end
|
127
|
+
|
128
|
+
# Destroy all of the contents of the directory, leaving it fresh and clean.
|
129
|
+
def purge
|
130
|
+
connection.purge full_path
|
131
|
+
end
|
132
|
+
|
133
|
+
# Text output of dir listing, equivalent to the regular unix shell's ls command.
|
134
|
+
def ls
|
135
|
+
out = [ "#{self}" ]
|
136
|
+
nonhidden_dirs.each do |dir|
|
137
|
+
out << " #{dir.name}/"
|
138
|
+
end
|
139
|
+
nonhidden_files.each do |file|
|
140
|
+
out << " #{file.name}"
|
141
|
+
end
|
142
|
+
out.join("\n")
|
143
|
+
end
|
144
|
+
|
145
|
+
# Run rake within this dir.
|
146
|
+
def rake(*args)
|
147
|
+
bash "rake #{args.join(' ')}"
|
148
|
+
end
|
149
|
+
|
150
|
+
# Run git within this dir.
|
151
|
+
def git(*args)
|
152
|
+
bash "git #{args.join(' ')}"
|
153
|
+
end
|
154
|
+
|
155
|
+
include Rush::Commands
|
156
|
+
|
157
|
+
def entries
|
158
|
+
contents
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rush/shell'
|
2
|
+
|
3
|
+
module Rush
|
4
|
+
# This is a class that can be embedded in other applications
|
5
|
+
# rake tasks, utility scripts, etc
|
6
|
+
#
|
7
|
+
# Delegates unknown method calls to a Rush::Shell instance
|
8
|
+
class EmbeddableShell
|
9
|
+
attr_accessor :shell
|
10
|
+
def initialize(suppress_output = true)
|
11
|
+
self.shell = Rush::Shell.new
|
12
|
+
shell.suppress_output = suppress_output
|
13
|
+
end
|
14
|
+
|
15
|
+
# evalutes and unkown method call agains the rush shell
|
16
|
+
def method_missing(sym, *args, &block)
|
17
|
+
shell.execute sym.to_s
|
18
|
+
$last_res
|
19
|
+
end
|
20
|
+
|
21
|
+
# take a whole block and execute it as if it were inside a shell
|
22
|
+
def execute_in_shell(&block)
|
23
|
+
self.instance_eval(&block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rush/entry.rb
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# Rush::Entry is the base class for Rush::File and Rush::Dir. One or more of
|
2
|
+
# these is instantiated whenever you use square brackets to access the
|
3
|
+
# filesystem on a box, as well as any other operation that returns an entry or
|
4
|
+
# list of entries.
|
5
|
+
class Rush::Entry
|
6
|
+
attr_reader :box, :name, :path
|
7
|
+
|
8
|
+
# Initialize with full path to the file or dir, and the box it resides on.
|
9
|
+
def initialize(full_path, box=nil)
|
10
|
+
full_path = ::File.expand_path(full_path, '/')
|
11
|
+
@path = ::File.dirname(full_path)
|
12
|
+
@name = ::File.basename(full_path)
|
13
|
+
@box = box || Rush::Box.new('localhost')
|
14
|
+
end
|
15
|
+
|
16
|
+
# The factory checks to see if the full path has a trailing slash for
|
17
|
+
# creating a Rush::Dir rather than the default Rush::File.
|
18
|
+
def self.factory(full_path, box=nil)
|
19
|
+
if full_path.tail(1) == '/'
|
20
|
+
Rush::Dir.new(full_path, box)
|
21
|
+
elsif File.directory?(full_path)
|
22
|
+
Rush::Dir.new(full_path, box)
|
23
|
+
else
|
24
|
+
Rush::File.new(full_path, box)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s # :nodoc:
|
29
|
+
if box.host == 'localhost'
|
30
|
+
"#{full_path}"
|
31
|
+
else
|
32
|
+
inspect
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect # :nodoc:
|
37
|
+
"#{box}:#{full_path}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def connection
|
41
|
+
box ? box.connection : Rush::Connection::Local.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# The parent dir. For example, box['/etc/hosts'].parent == box['etc/']
|
45
|
+
def parent
|
46
|
+
@parent ||= Rush::Dir.new(@path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def full_path
|
50
|
+
"#{@path}/#{@name}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def quoted_path
|
54
|
+
Rush.quote(full_path)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return true if the entry currently exists on the filesystem of the box.
|
58
|
+
def exists?
|
59
|
+
stat
|
60
|
+
true
|
61
|
+
rescue Rush::DoesNotExist
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
# Timestamp of most recent change to the entry (permissions, contents, etc).
|
66
|
+
def changed_at
|
67
|
+
stat[:ctime]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Timestamp of last modification of the contents.
|
71
|
+
def last_modified
|
72
|
+
stat[:mtime]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Timestamp that entry was last accessed (read from or written to).
|
76
|
+
def last_accessed
|
77
|
+
stat[:atime]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Attempts to rename, copy, or otherwise place an entry into a dir that already contains an entry by that name will fail with this exception.
|
81
|
+
class NameAlreadyExists < Exception; end
|
82
|
+
|
83
|
+
# Do not use rename or duplicate with a slash; use copy_to or move_to instead.
|
84
|
+
class NameCannotContainSlash < Exception; end
|
85
|
+
|
86
|
+
# Rename an entry to another name within the same dir. The object's name
|
87
|
+
# will be updated to match the change on the filesystem.
|
88
|
+
def rename(new_name)
|
89
|
+
connection.rename(@path, @name, new_name)
|
90
|
+
@name = new_name
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
# Rename an entry to another name within the same dir. The existing object
|
95
|
+
# will not be affected, but a new object representing the newly-created
|
96
|
+
# entry will be returned.
|
97
|
+
def duplicate(new_name)
|
98
|
+
raise Rush::NameCannotContainSlash if new_name.match(/\//)
|
99
|
+
new_full_path = "#{@path}/#{new_name}"
|
100
|
+
connection.copy(full_path, new_full_path)
|
101
|
+
self.class.new(new_full_path, box)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Copy the entry to another dir. Returns an object representing the new
|
105
|
+
# copy.
|
106
|
+
def copy_to(dir)
|
107
|
+
raise Rush::NotADir unless dir.class == Rush::Dir
|
108
|
+
|
109
|
+
if box == dir.box
|
110
|
+
connection.copy(full_path, dir.full_path)
|
111
|
+
else
|
112
|
+
archive = connection.read_archive(full_path)
|
113
|
+
dir.box.connection.write_archive(archive, dir.full_path)
|
114
|
+
end
|
115
|
+
|
116
|
+
new_full_path = "#{dir.full_path}#{name}"
|
117
|
+
self.class.new(new_full_path, dir.box)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Move the entry to another dir. The object will be updated to show its new
|
121
|
+
# location.
|
122
|
+
def move_to(dir)
|
123
|
+
moved = copy_to(dir)
|
124
|
+
destroy
|
125
|
+
mimic(moved)
|
126
|
+
end
|
127
|
+
|
128
|
+
def mimic(from) # :nodoc:
|
129
|
+
@box = from.box
|
130
|
+
@path = from.path
|
131
|
+
@name = from.name
|
132
|
+
end
|
133
|
+
|
134
|
+
# Unix convention considers entries starting with a . to be hidden.
|
135
|
+
def hidden?
|
136
|
+
name.slice(0, 1) == '.'
|
137
|
+
end
|
138
|
+
|
139
|
+
# Set the access permissions for the entry.
|
140
|
+
#
|
141
|
+
# Permissions are set by role and permissions combinations which can be specified individually
|
142
|
+
# or grouped together. :user_can => :read, :user_can => :write is the same
|
143
|
+
# as :user_can => :read_write.
|
144
|
+
#
|
145
|
+
# You can also insert 'and' if you find it reads better, like :user_and_group_can => :read_and_write.
|
146
|
+
#
|
147
|
+
# Any permission excluded is set to deny access. The access call does not set partial
|
148
|
+
# permissions which combine with the existing state of the entry, like "chmod o+r" would.
|
149
|
+
#
|
150
|
+
# Examples:
|
151
|
+
#
|
152
|
+
# file.access = { :user_can => :read_write, :group_other_can => :read }
|
153
|
+
# dir.access = { :user => 'adam', :group => 'users', :read_write_execute => :user_group }
|
154
|
+
#
|
155
|
+
def access=(options)
|
156
|
+
connection.set_access(full_path, Rush::Access.parse(options))
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns a hash with up to nine values, combining user/group/other with read/write/execute.
|
160
|
+
# The key is omitted if the value is false.
|
161
|
+
#
|
162
|
+
# Examples:
|
163
|
+
#
|
164
|
+
# entry.access # -> { :user_can_read => true, :user_can_write => true, :group_can_read => true }
|
165
|
+
# entry.access[:other_can_read] # -> true or nil
|
166
|
+
#
|
167
|
+
def access
|
168
|
+
Rush::Access.new.from_octal(stat[:mode]).display_hash
|
169
|
+
end
|
170
|
+
|
171
|
+
# Destroy the entry. If it is a dir, everything inside it will also be destroyed.
|
172
|
+
def destroy
|
173
|
+
connection.destroy(full_path)
|
174
|
+
end
|
175
|
+
|
176
|
+
def ==(other) # :nodoc:
|
177
|
+
full_path == other.full_path and box == other.box
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
def stat
|
183
|
+
connection.stat(full_path)
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rush
|
2
|
+
# Base class for all rush exceptions.
|
3
|
+
class Exception < ::RuntimeError; end
|
4
|
+
|
5
|
+
# Client was not authorized by remote server; check credentials.
|
6
|
+
class NotAuthorized < Exception; end
|
7
|
+
|
8
|
+
# rushd is not running on the remote box.
|
9
|
+
class RushdNotRunning < Exception; end
|
10
|
+
|
11
|
+
# An unrecognized status code was returned by rushd.
|
12
|
+
class FailedTransmit < Exception; end
|
13
|
+
|
14
|
+
# The entry (file or dir) referenced does not exist. Message is the entry's full path.
|
15
|
+
class DoesNotExist < Exception; end
|
16
|
+
|
17
|
+
# The bash command had a non-zero return value. Message is stderr.
|
18
|
+
class BashFailed < Exception; end
|
19
|
+
|
20
|
+
# There's already an entry by the given name in the given dir.
|
21
|
+
class NameAlreadyExists < Exception; end
|
22
|
+
|
23
|
+
# The name cannot contain a slash; use two operations, rename and then move, instead.
|
24
|
+
class NameCannotContainSlash < Exception; end
|
25
|
+
|
26
|
+
# You cannot move or copy entries to a path that is not a dir (should end with trailing slash).
|
27
|
+
class NotADir < Exception; end
|
28
|
+
|
29
|
+
# A user or permission value specified to set access was not valid.
|
30
|
+
class BadAccessSpecifier < Exception; end
|
31
|
+
end
|
data/lib/rush/file.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Files are a subclass of Rush::Entry. Most of the file-specific operations
|
2
|
+
# relate to manipulating the file's contents, like search and replace.
|
3
|
+
class Rush::File < Rush::Entry
|
4
|
+
def dir?
|
5
|
+
false
|
6
|
+
end
|
7
|
+
|
8
|
+
# Create a blank file.
|
9
|
+
def create
|
10
|
+
write('')
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
# Size in bytes on disk.
|
15
|
+
def size
|
16
|
+
stat[:size]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Raw contents of the file. For non-text files, you probably want to avoid
|
20
|
+
# printing this on the screen.
|
21
|
+
def contents
|
22
|
+
connection.file_contents(full_path)
|
23
|
+
end
|
24
|
+
|
25
|
+
alias :read :contents
|
26
|
+
|
27
|
+
# Write to the file, overwriting whatever was already in it.
|
28
|
+
#
|
29
|
+
# Example: file.write "hello, world\n"
|
30
|
+
def write(new_contents)
|
31
|
+
connection.write_file(full_path, new_contents)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Append new contents to the end of the file, keeping what was in it.
|
35
|
+
def append(contents)
|
36
|
+
connection.append_to_file(full_path, contents)
|
37
|
+
end
|
38
|
+
alias_method :<<, :append
|
39
|
+
|
40
|
+
# Return an array of lines from the file, similar to stdlib's File#readlines.
|
41
|
+
def lines
|
42
|
+
contents.split("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Search the file's for a regular expression. Returns nil if no match, or
|
46
|
+
# each of the matching lines in its entirety.
|
47
|
+
#
|
48
|
+
# Example: box['/etc/hosts'].search(/localhost/) # -> [ "127.0.0.1 localhost\n", "::1 localhost\n" ]
|
49
|
+
def search(pattern)
|
50
|
+
matching_lines = lines.select { |line| line.match(pattern) }
|
51
|
+
matching_lines.size == 0 ? nil : matching_lines
|
52
|
+
end
|
53
|
+
|
54
|
+
# Search-and-replace file contents.
|
55
|
+
#
|
56
|
+
# Example: box['/etc/hosts'].replace_contents!(/localhost/, 'local.host')
|
57
|
+
def replace_contents!(pattern, replace_with)
|
58
|
+
write contents.gsub(pattern, replace_with)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return the file's contents, or if it doesn't exist, a blank string.
|
62
|
+
def contents_or_blank
|
63
|
+
contents
|
64
|
+
rescue Rush::DoesNotExist
|
65
|
+
""
|
66
|
+
end
|
67
|
+
|
68
|
+
# Count the number of lines in the file.
|
69
|
+
def line_count
|
70
|
+
lines.size
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return an array of lines, or an empty array if the file does not exist.
|
74
|
+
def lines_or_empty
|
75
|
+
lines
|
76
|
+
rescue Rush::DoesNotExist
|
77
|
+
[]
|
78
|
+
end
|
79
|
+
|
80
|
+
include Rush::Commands
|
81
|
+
|
82
|
+
def entries
|
83
|
+
[ self ]
|
84
|
+
end
|
85
|
+
end
|
data/lib/rush/find_by.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Generic find_by (returns first match) and find_all_by (returns all matches)
|
2
|
+
# against arrays.
|
3
|
+
#
|
4
|
+
# Examples:
|
5
|
+
#
|
6
|
+
# processes.find_by_pid(::Process.pid)
|
7
|
+
# processes.find_all_by_cmdline(/mongrel_rails/)
|
8
|
+
#
|
9
|
+
module Rush::FindBy
|
10
|
+
def method_missing(meth, *args)
|
11
|
+
if m = meth.to_s.match(/^find_by_([a-z_]+)$/)
|
12
|
+
find_by(m[1], args.first)
|
13
|
+
elsif m = meth.to_s.match(/^find_all_by_([a-z_]+)$/)
|
14
|
+
find_all_by(m[1], args.first)
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_by(field, arg)
|
21
|
+
detect do |item|
|
22
|
+
item.respond_to?(field) and compare_or_match(item.send(field), arg)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_all_by(field, arg)
|
27
|
+
select do |item|
|
28
|
+
item.respond_to?(field) and compare_or_match(item.send(field), arg)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def compare_or_match(value, against)
|
33
|
+
if against.class == Regexp
|
34
|
+
value.match(against) ? true : false
|
35
|
+
else
|
36
|
+
value == against
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Integer extensions for file and dir sizes (returned in bytes).
|
2
|
+
#
|
3
|
+
# Example:
|
4
|
+
#
|
5
|
+
# box['/assets/'].files_flattened.select { |f| f.size > 10.mb }
|
6
|
+
class Fixnum
|
7
|
+
def kb
|
8
|
+
self * 1024
|
9
|
+
end
|
10
|
+
|
11
|
+
def mb
|
12
|
+
kb * 1024
|
13
|
+
end
|
14
|
+
|
15
|
+
def gb
|
16
|
+
mb * 1024
|
17
|
+
end
|
18
|
+
end
|