Skip to content

Instantly share code, notes, and snippets.

@bcardiff
Created June 18, 2014 20:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bcardiff/9b3ee7c86f6c9c0a5077 to your computer and use it in GitHub Desktop.
Save bcardiff/9b3ee7c86f6c9c0a5077 to your computer and use it in GitHub Desktop.
file system abstraction for crystal
macro collect_alias_method(method, type)
def {{method}}
res = [] of {{type}}
{{method}} do |e|
res << e
end
res
end
end
module FS
module FileContainer
def files(&block : FileEntry -> U)
entries do |e|
block.call(e) if e.is_a?(FileEntry)
end
end
collect_alias_method "files", "FileEntry"
def dirs(&block : DirectoryEntry -> U)
entries do |e|
block.call(e) if e.is_a?(DirectoryEntry)
end
end
collect_alias_method "dirs", "DirectoryEntry"
end
class Entry
def initialize(@fs, @path)
end
# the name of the file or directory
def name
File.basename(@path)
end
# the relative path from the filesystem
# requesting this path to the filesystem
# should get an equivalent entry
def path
@path
end
def file?
false
end
def dir?
false
end
end
class FileEntry < Entry
def file?
true
end
def read
@fs.read(path)
end
end
class DirectoryEntry < Entry
include FileContainer
def dir?
true
end
def open(file_name)
@fs.open(scoped_file_name(file_name))
end
def entries(&block : Entry+ -> U)
@fs.find_entries(scoped_file_name(""), &block)
end
collect_alias_method "entries", "Entry+"
# private
def scoped_file_name(file_name)
@fs.combine path, file_name
end
end
class FileSystem
include FileContainer
def combine(a, b)
if b.empty?
a
else
"#{a}/#{b}"
end
end
end
class FileSystemDirectory < FileSystem
def initialize(@path)
end
def read(file_name)
File.read scoped_file_name(file_name)
end
def entries(&block : Entry+ -> U)
find_entries("", &block)
end
collect_alias_method "entries", "Entry+"
def find_entries(path, &block : Entry+ -> U)
Dir.list(scoped_file_name(path)) do |entry, type|
next if entry == "." || entry == ".."
block.call(create_entry(combine(path, entry), type))
end
end
collect_alias_method "find_entries(path)", "Entry+"
# private
def create_entry(entry, type)
if type == C::DirType::DIR
DirectoryEntry.new(self, entry)
# else
elsif type == C::DirType::REG
FileEntry.new(self, entry)
else
raise "not implemented"
end
end
def scoped_file_name(file_name)
combine @path, file_name
end
end
end
fs = FS::FileSystemDirectory.new("/Users/bcardiff/Work/Manas/crystal/src")
puts fs.read("min.c")
# fs.find_entries("samples") do |f|
# puts f.name
# puts f.path
# exit
# end
# fs.entries do |a|
# if a.is_a?(FS::DirectoryEntry) && a.name == "samples"
# a.entries do |e|
# puts e.path
# if e.is_a?(FS::FileEntry)
# puts "#{e.name}, #{e.path}"
# end
# end
# end
# end
puts fs.files.first.name
a = fs.dirs.select { |a| a.name == "samples" }.first
e = a.files.first
puts "#{e.name}, #{e.path}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment