Skip to content

Commit

Permalink
Merge a04c7ef into d193d7d
Browse files Browse the repository at this point in the history
  • Loading branch information
mjacobus committed Apr 28, 2020
2 parents d193d7d + a04c7ef commit 4df2dc5
Show file tree
Hide file tree
Showing 16 changed files with 626 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
# rspec failure tracking
.rspec_status
/Gemfile.lock
/spec/fixtures/sandbox
6 changes: 5 additions & 1 deletion lib/koine/file_system.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# frozen_string_literal: true

require 'koine/file_system/version'
require 'koine/file_system/file_system'
require 'koine/file_system/path_sanitizer'
require 'koine/file_system/adapters/base'
require 'koine/file_system/adapters/local'

module Koine
module FileSystem
class Error < StandardError; end
# Your code goes here...
class FileNotFound < Error; end
end
end
160 changes: 160 additions & 0 deletions lib/koine/file_system/adapters/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# frozen_string_literal: true

module Koine
module FileSystem
module Adapters
# rubocop:disable Lint/UnusedMethodArgument
class Base
# @param path [String] path
#
# @return string
#
# @raise [FileNotFound] when file does not exist or cannot be read
def read(path)
raise NotImplementedError
end

# @param path [String] path
#
# @return Boolean
#
# @raise [FileNotFound] when file does not exist or cannot be read
def read_stream(path)
raise NotImplementedError
end

# @param path [String] path
# @param contents [String] the content
# @param options [<Hash>] the options
#
# @return [void]
def write(path, contents, options: {})
raise NotImplementedError
end

# @param path [String] path
# @param contents [String] the content
# @param options [<Hash>] the options
#
# @return [void]
def write_stream(path, contents, options: {})
raise NotImplementedError
end

# @param path [String] path
# @param contents [String] the new content
# @param options [<Hash>] the options
#
# @return [void]
#
# @raise [FileNotFound] when file does not exist or cannot be read
def update(path, contents, options: {})
raise NotImplementedError
end

# @param path [String] path
# @param contents [String] the new content
# @param options [<Hash>] the options
#
# @return [void]
#
# @raise [FileNotFound] when file does not exist or cannot be read
def update_stream(path, contents, options: {})
raise NotImplementedError
end

# @param path [String] path
#
# @return Boolean
def has?(path)
raise NotImplementedError
end

# @param path [String] path
#
# @return [void]
#
# @raise [FileNotFound] when file does not exist or cannot be read
def delete(path)
raise NotImplementedError
end

# @param path [String] path
#
# @return [String]
#
# @raise [FileNotFound] when file does not exist or cannot be read
def read_and_delete(path)
raise NotImplementedError
end

# @param from [String] path
# @param to [String] path
#
# @return [void]
#
# @raise [FileNotFound] when source file does not exist or cannot be read
def rename(from, to)
raise NotImplementedError
end

# @param from [String] path
# @param to [String] path
#
# @return [void]
#
# @raise [FileNotFound] when source file does not exist or cannot be read
def copy(from, to)
raise NotImplementedError
end

# @param path [String] path
#
# @return [String]
#
# @raise [FileNotFound] when source file does not exist or cannot be read
def mime_type(path)
raise NotImplementedError
end

# @param path [String] path
#
# @return [Integer] Number of bytes
#
# @raise [FileNotFound] when file does not exist or cannot be read
def size(path)
raise NotImplementedError
end

# @param path [String] path
#
# @return [void]
def create_dir(path)
raise NotImplementedError
end

# @param path [String] path
#
# @return [void]
def delete_dir(path)
raise NotImplementedError
end

# @param path [String] path
# @param recursive [Bool] path
#
# @return [void]
def list(path, recursive: false)
raise NotImplementedError
end

private

def raise_not_found(file)
raise FileNotFound, "File not found: #{file}"
end
end
# rubocop:enable Lint/UnusedMethodArgument
end
end
end
68 changes: 68 additions & 0 deletions lib/koine/file_system/adapters/local.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true

require 'fileutils'

module Koine
module FileSystem
module Adapters
# rubocop:disable Lint/UnusedMethodArgument
class Local < Base
def initialize(root:, path_sanitizer: PathSanitizer.new)
@root = root
@path_sanitizer = path_sanitizer
end

def read(path)
if has?(path)
file = File.open(full_path(path), 'rb')
content = file.read
file.close
return content
end
raise_not_found(path)
end

def has?(path)
File.exist?(full_path(path))
end

def write(path, content, options: {})
path = full_path(path)
ensure_target_dir(path)
File.open(path, 'w') do |f|
f.write(content)
end
end

private

def full_path(path)
File.expand_path(sanitize_path(path), @root)
end

def ensure_target_dir(path)
dir = File.dirname(path)
unless Dir.exist?(dir)
FileUtils.mkdir_p(dir)
end
end

def sanitize_path(path)
@path_sanitizer.sanitize(path)
end

# def update(_path, _contents, options: {})
# def delete(_path)
# def read_and_delete(_path)
# def rename(_from, _to)
# def copy(_from, _to)
# def mime_type(_path)
# def size(_path)
# def create_dir(_path)
# def delete_dir(_path)
# def list(_path, recursive: false)
end
# rubocop:enable Lint/UnusedMethodArgument
end
end
end
77 changes: 77 additions & 0 deletions lib/koine/file_system/file_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true

module Koine
module FileSystem
# Inspired on
# https://flysystem.thephpleague.com/v1/docs/usage/filesystem-api/
class FileSystem
def initialize(adapter)
@adapter = adapter
end

def read(path, &block)
@adapter.read(path, &block)
end

def read_stream(path, &block)
@adapter.read_stream(path, &block)
end

def write(path, contents, options: {})
@adapter.write(path, contents, options: options)
end

def write_stream(path, contents, options: {})
@adapter.write_stream(path, contents, options: options)
end

def update(path, contents, options: {})
@adapter.update(path, contents, options: options)
end

def update_stream(path, contents, options: {})
@adapter.update_stream(path, contents, options: options)
end

def has?(path)
@adapter.has?(path)
end

def delete(path)
@adapter.delete(path)
end

def read_and_delete(path)
@adapter.read_and_delete(path)
end

def rename(from, to)
@adapter.rename(from, to)
end

def copy(from, to)
@adapter.copy(from, to)
end

def mime_type(path)
@adapter.mime_type(path)
end

def size(path)
@adapter.size(path)
end

def create_dir(path)
@adapter.create_dir(path)
end

def delete_dir(path)
@adapter.delete_dir(path)
end

def list(path, recursive: false)
@adapter.list(path, recursive: recursive)
end
end
end
end
13 changes: 13 additions & 0 deletions lib/koine/file_system/path_sanitizer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require 'fileutils'

module Koine
module FileSystem
class PathSanitizer
def sanitize(path)
path.to_s.gsub('/../', '/').gsub(%r{\.?\./}, '')
end
end
end
end
1 change: 1 addition & 0 deletions spec/fixtures/list_sandbox/folder1/folder2/sample.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is folder1/folder2/sample.txt
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions spec/fixtures/list_sandbox/sample.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This is a sample file
For local adapter
Empty file added spec/fixtures/sample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions spec/fixtures/sample.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This is a sample file
For local adapter
Loading

0 comments on commit 4df2dc5

Please sign in to comment.