Class: Staticky::Files

Inherits:
Object
  • Object
show all
Defined in:
lib/staticky/files.rb,
lib/staticky/files/path.rb,
lib/staticky/files/error.rb,
lib/staticky/files/adapter.rb,
lib/staticky/files/version.rb,
lib/staticky/files/file_system.rb,
lib/staticky/files/memory_file_system.rb,
lib/staticky/files/memory_file_system/node.rb

Overview

rubocop:disable Metrics/ClassLength

Defined Under Namespace

Modules: Path Classes: Adapter, Delimiter, Error, FileSystem, IOError, MemoryFileSystem, MissingTargetError, NotMemoryFileError, UnknownMemoryNodeError

Constant Summary collapse

OPEN_MODE =
::File::RDWR
WRITE_MODE =
(::File::CREAT | ::File::WRONLY | ::File::TRUNC).freeze
VERSION =
"0.1.0"

Instance Method Summary collapse

Constructor Details

#initialize(memory: false, adapter: Adapter.call(memory:)) ⇒ Staticky::Files

Creates a new instance

Memory file system is experimental

Parameters:

  • memory (TrueClass, FalseClass) (defaults to: false)

    use in-memory, ephemeral file system

  • adapter (Staticky::FileSystem) (defaults to: Adapter.call(memory:))


20
21
22
# File 'lib/staticky/files.rb', line 20

def initialize(memory: false, adapter: Adapter.call(memory:))
  @adapter = adapter
end

Instance Method Details

#append(path, contents) ⇒ Object

Adds a new line at the bottom of the file

Parameters:

  • path (String, Pathname)

    the path to file

  • contents (String)

    the contents to add

Raises:

See Also:

Since:

  • 0.1.0



316
317
318
319
320
321
322
323
324
325
# File 'lib/staticky/files.rb', line 316

def append(path, contents)
  mkdir_p(path)
  touch(path)

  content = adapter.readlines(path)
  content << newline unless newline?(content.last)
  content << newline(contents)

  write(path, content)
end

#chdir(path, &blk) ⇒ Object

Temporary changes the current working directory of the process to the given path and yield the given block.

Parameters:

  • path (String, Pathname)

    the target directory

  • blk (Proc)

    the code to execute with the target directory

Raises:



131
132
133
# File 'lib/staticky/files.rb', line 131

def chdir(path, &blk)
  adapter.chdir(path, &blk)
end

#chmod(path, mode) ⇒ Object

Sets UNIX permissions of the file at the given path.

Accepts permissions in numeric mode only, best provided as octal numbers matching the standard UNIX octal permission modes, such as ‘0o544` for a file writeable by its owner and readable by others, or `0o755` for a file writeable by its owner and executable by everyone.

Parameters:

  • path (String, Pathname)

    the path to the file

  • mode (Integer)

    the UNIX permissions mode

Raises:



69
70
71
72
73
74
75
76
# File 'lib/staticky/files.rb', line 69

def chmod(path, mode)
  unless mode.is_a?(Integer)
    raise Staticky::Files::Error,
          "mode should be an integer (e.g. 0o755)"
  end

  adapter.chmod(path, mode)
end

#cp(source, destination) ⇒ Object

Copies source into destination. All the intermediate directories are created. If the destination already exists, it overrides the contents.

Parameters:

  • source (String, Pathname)

    the path to the source file

  • destination (String, Pathname)

    the path to the destination file

Raises:

Since:

  • 0.1.0



199
200
201
# File 'lib/staticky/files.rb', line 199

def cp(source, destination)
  adapter.cp(source, destination)
end

#delete(path) ⇒ Object

Deletes given path (file).

Parameters:

  • path (String, Pathname)

    the path to file

Raises:

Since:

  • 0.1.0



211
212
213
# File 'lib/staticky/files.rb', line 211

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

#delete_directory(path) ⇒ Object

Deletes given path (directory).

Parameters:

  • path (String, Pathname)

    the path to file

Raises:

Since:

  • 0.1.0



223
224
225
# File 'lib/staticky/files.rb', line 223

def delete_directory(path)
  adapter.rm_rf(path)
end

#directory?(path) ⇒ TrueClass, FalseClass

Checks if ‘path` is a directory

Examples:

require "staticky/files"

Staticky::Files.new.directory?(__dir__)  # => true
Staticky::Files.new.directory?(__FILE__) # => false

Staticky::Files.new.directory?("missing_directory") # => false

Parameters:

  • path (String, Pathname)

    the path to directory

Returns:

  • (TrueClass, FalseClass)

    the result of the check

Since:

  • 0.1.0



263
264
265
# File 'lib/staticky/files.rb', line 263

def directory?(path)
  adapter.directory?(path)
end

#entries(path) ⇒ Object

Reads entries from a directory

Parameters:

  • path (String, Pathname)

    the path to file

Raises:

Since:

  • 1.0.1



842
843
844
# File 'lib/staticky/files.rb', line 842

def entries(path)
  adapter.entries(path)
end

#executable?(path) ⇒ TrueClass, FalseClass

Checks if ‘path` is an executable

Examples:

require "staticky/files"

Staticky::Files.new.executable?("/path/to/ruby") # => true
Staticky::Files.new.executable?(__FILE__)        # => false

Staticky::Files.new.directory?("missing_file") # => false

Parameters:

  • path (String, Pathname)

    the path to file

Returns:

  • (TrueClass, FalseClass)

    the result of the check

Since:

  • 0.1.0



283
284
285
# File 'lib/staticky/files.rb', line 283

def executable?(path)
  adapter.executable?(path)
end

#exist?(path) ⇒ TrueClass, FalseClass

Checks if ‘path` exist

Examples:

require "staticky/files"

Staticky::Files.new.exist?(__FILE__) # => true
Staticky::Files.new.exist?(__dir__)  # => true

Staticky::Files.new.exist?("missing_file") # => false

Parameters:

  • path (String, Pathname)

    the path to file

Returns:

  • (TrueClass, FalseClass)

    the result of the check

Since:

  • 0.1.0



243
244
245
# File 'lib/staticky/files.rb', line 243

def exist?(path)
  adapter.exist?(path)
end

#expand_path(path, dir = pwd) ⇒ String

Converts a path to an absolute path.

Relative paths are referenced from the current working directory of the process unless ‘dir` is given.

Parameters:

  • path (String, Pathname)

    the path to the file

  • dir (String, Pathname) (defaults to: pwd)

    the base directory

Returns:

  • (String)

    the expanded path



97
98
99
# File 'lib/staticky/files.rb', line 97

def expand_path(path, dir = pwd)
  adapter.expand_path(path, dir)
end

#inject_line_after(path, target, contents) ⇒ Object

Inject ‘contents` in `path` after `target`.

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target to replace

  • contents (String)

    the contents to inject

Raises:

See Also:

Since:

  • 0.1.0



421
422
423
# File 'lib/staticky/files.rb', line 421

def inject_line_after(path, target, contents)
  _inject_line_after(path, target, contents, method(:index))
end

#inject_line_after_last(path, target, contents) ⇒ Object

Inject ‘contents` in `path` after last `target`.

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target to replace

  • contents (String)

    the contents to inject

Raises:

See Also:

Since:

  • 0.1.0



440
441
442
# File 'lib/staticky/files.rb', line 440

def inject_line_after_last(path, target, contents)
  _inject_line_after(path, target, contents, method(:rindex))
end

#inject_line_at_block_bottom(path, target, *contents) ⇒ Object

Inject ‘contents` in `path` within the first Ruby block that matches `target`. The given `contents` will appear at the BOTTOM of the Ruby block.

Examples:

Inject a single line

require "staticky/files"

files = Staticky::Files.new
path = "config/application.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#   end
# end

# inject a single line
files.inject_line_at_block_bottom(path, /configure/, %(load_path.unshift("lib")))

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#     load_path.unshift("lib")
#   end
# end

Inject multiple lines

require "staticky/files"

files = Staticky::Files.new
path = "config/application.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#   end
# end

# inject multiple lines
files.inject_line_at_block_bottom(path,
                                  /configure/,
                                  [%(load_path.unshift("lib")), "settings.load!"])

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#     load_path.unshift("lib")
#     settings.load!
#   end
# end

Inject a block

require "staticky/files"

files = Staticky::Files.new
path = "config/application.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#   end
# end

# inject a block
block = <<~BLOCK
  settings do
    load!
  end
BLOCK
files.inject_line_at_block_bottom(path, /configure/, block)

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#     settings do
#       load!
#     end
#   end
# end

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target matcher for Ruby block

  • contents (String, Array<String>)

    the contents to inject

Raises:

Since:

  • 0.1.0



668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
# File 'lib/staticky/files.rb', line 668

def inject_line_at_block_bottom(path, target, *contents)
  content   = adapter.readlines(path)
  starting  = index(content, path, target)
  line      = content[starting]
  delimiter = if line.match?(INLINE_OPEN_BLOCK_MATCHER)
    INLINE_BLOCK_DELIMITER
  else
    BLOCK_DELIMITER
  end
  target    = content[starting..]
  ending    = closing_block_index(target, starting, path, line, delimiter)
  offset    = SPACE * (content[ending][SPACE_MATCHER].bytesize + INDENTATION)

  contents = Array(contents).flatten
  contents = _offset_block_lines(contents, offset)

  content.insert(ending, contents)
  write(path, content)
end

#inject_line_at_block_top(path, target, *contents) ⇒ Object

Inject ‘contents` in `path` within the first Ruby block that matches `target`. The given `contents` will appear at the TOP of the Ruby block.

Examples:

Inject a single line

require "staticky/files"

files = Staticky::Files.new
path = "config/application.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#   end
# end

# inject a single line
files.inject_line_at_block_top(path, /configure/, %(load_path.unshift("lib")))

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     load_path.unshift("lib")
#     root __dir__
#   end
# end

Inject multiple lines

require "staticky/files"

files = Staticky::Files.new
path = "config/application.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#   end
# end

# inject multiple lines
files.inject_line_at_block_top(path,
                               /configure/,
                               [%(load_path.unshift("lib")), "settings.load!"])

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     load_path.unshift("lib")
#     settings.load!
#     root __dir__
#   end
# end

Inject a block

require "staticky/files"

files = Staticky::Files.new
path = "config/application.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     root __dir__
#   end
# end

# inject a block
block = <<~BLOCK
  settings do
    load!
  end
BLOCK
files.inject_line_at_block_top(path, /configure/, block)

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   configure do
#     settings do
#       load!
#     end
#     root __dir__
#   end
# end

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target matcher for Ruby block

  • contents (String, Array<String>)

    the contents to inject

Raises:

Since:

  • 0.1.0



550
551
552
553
554
555
556
557
558
559
560
# File 'lib/staticky/files.rb', line 550

def inject_line_at_block_top(path, target, *contents)
  content  = adapter.readlines(path)
  starting = index(content, path, target)
  offset   = SPACE * (content[starting][SPACE_MATCHER].bytesize + INDENTATION)

  contents = Array(contents).flatten
  contents = _offset_block_lines(contents, offset)

  content.insert(starting + CONTENT_OFFSET, contents)
  write(path, content)
end

#inject_line_at_class_bottom(path, target, *contents) ⇒ Object

Inject ‘contents` in `path` at the bottom of the Ruby class that matches `target`. The given `contents` will appear at the BOTTOM of the Ruby class.

Examples:

Inject a single line

require "staticky/files"

files = Staticky::Files.new
path = "config/application.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Application
# end

# inject a single line
files.inject_line_at_class_bottom(path, /Application/, %(attr_accessor :name))

File.read(path)
# # frozen_string_literal: true
#
# class Application
#   attr_accessor :name
# end

Inject multiple lines

require "staticky/files"

files = Staticky::Files.new
path = "math.rb"

File.read(path)
# # frozen_string_literal: true
#
# class Math
# end

# inject multiple lines
files.inject_line_at_class_bottom(path,
                                  /Math/,
                                  ["def sum(a, b)", "  a + b", "end"])

File.read(path)
# # frozen_string_literal: true
#
# class Math
#   def sum(a, b)
#     a + b
#   end
# end

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target matcher for Ruby class

  • contents (String, Array<String>)

    the contents to inject

Raises:

Since:

  • 0.4.0



748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
# File 'lib/staticky/files.rb', line 748

def inject_line_at_class_bottom(path, target, *contents)
  content   = adapter.readlines(path)
  starting  = index(content, path, target)
  line      = content[starting]
  target    = content[starting..]
  ending    = closing_class_index(
    target,
    starting,
    path,
    line,
    BLOCK_DELIMITER
  )
  offset = SPACE * (content[ending][SPACE_MATCHER].bytesize + INDENTATION)

  contents = Array(contents).flatten
  contents = _offset_block_lines(contents, offset)

  content.insert(ending, contents)
  write(path, content)
end

#inject_line_before(path, target, contents) ⇒ Object

Inject ‘contents` in `path` before `target`.

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target to replace

  • contents (String)

    the contents to inject

Raises:

See Also:

Since:

  • 0.1.0



383
384
385
# File 'lib/staticky/files.rb', line 383

def inject_line_before(path, target, contents)
  _inject_line_before(path, target, contents, method(:index))
end

#inject_line_before_last(path, target, contents) ⇒ Object

Inject ‘contents` in `path` after last `target`.

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target to replace

  • contents (String)

    the contents to inject

Raises:

See Also:

Since:

  • 0.1.0



402
403
404
# File 'lib/staticky/files.rb', line 402

def inject_line_before_last(path, target, contents)
  _inject_line_before(path, target, contents, method(:rindex))
end

#join(*path) ⇒ String

Returns a new string formed by joining the strings using Operating System path separator

Parameters:

  • path (Array<String,Pathname>)

    path tokens

Returns:

  • (String)

    the joined path



84
85
86
# File 'lib/staticky/files.rb', line 84

def join(*path)
  adapter.join(*path)
end

#mkdir(path) ⇒ Object

Creates a directory for the given path. It assumes that all the tokens in ‘path` are meant to be a directory. All the intermediate directories are created.

Examples:

require "staticky/files"

Staticky::Files.new.mkdir("path/to/directory")
  # => creates the `path/to/directory` directory

# WRONG this isn't probably what you want, check `.mkdir_p`
Staticky::Files.new.mkdir("path/to/file.rb")
  # => creates the `path/to/file.rb` directory

Parameters:

  • path (String, Pathname)

    the path to directory

Raises:

See Also:

Since:

  • 0.1.0



157
158
159
# File 'lib/staticky/files.rb', line 157

def mkdir(path)
  adapter.mkdir(path)
end

#mkdir_p(path) ⇒ Object

Creates a directory for the given path. It assumes that all the tokens, but the last, in ‘path` are meant to be a directory, whereas the last is meant to be a file. All the intermediate directories are created.

Examples:

require "staticky/files"

Staticky::Files.new.mkdir_p("path/to/file.rb")
  # => creates the `path/to` directory, but NOT `file.rb`

# WRONG it doesn't create the last directory, check `.mkdir`
Staticky::Files.new.mkdir_p("path/to/directory")
  # => creates the `path/to` directory

Parameters:

  • path (String, Pathname)

    the path to directory

Raises:

See Also:

Since:

  • 0.1.0



184
185
186
# File 'lib/staticky/files.rb', line 184

def mkdir_p(path)
  adapter.mkdir_p(path)
end

#open(path, mode = OPEN_MODE) {|the| ... } ⇒ File, Staticky::Files::MemoryFileSystem::Node

Opens (or creates) a new file for both read/write operations

Parameters:

  • path (String)

    the target file

  • mode (String, Integer) (defaults to: OPEN_MODE)

    Ruby file open mode

  • args (Array<Object>)

    ::File.open args

  • blk (Proc)

    the block to yield

Yield Parameters:

Returns:

Raises:



120
121
122
# File 'lib/staticky/files.rb', line 120

def open(path, mode = OPEN_MODE, ...)
  adapter.open(path, mode, ...)
end

#pwdString

Returns the name of the current working directory.

Returns:

  • (String)

    the current working directory.



104
105
106
# File 'lib/staticky/files.rb', line 104

def pwd
  adapter.pwd
end

#read(path) ⇒ String

Read file content

TODO: allow buffered read

Parameters:

  • path (String, Pathname)

    the path to file

Returns:

  • (String)

    the file contents

Raises:



32
33
34
# File 'lib/staticky/files.rb', line 32

def read(path)
  adapter.read(path)
end

#remove_block(path, target) ⇒ Object

Removes ‘target` block from `path`

Examples:

require "staticky/files"

puts File.read("app.rb")

# class App
#   configure do
#     root __dir__
#   end
# end

Staticky::Files.new.remove_block("app.rb", "configure")

puts File.read("app.rb")

# class App
# end

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String)

    the target block to remove

Raises:

Since:

  • 0.1.0



815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
# File 'lib/staticky/files.rb', line 815

def remove_block(path, target)
  content  = adapter.readlines(path)
  starting = index(content, path, target)
  line     = content[starting]
  size     = line[SPACE_MATCHER].bytesize
  closing  = (SPACE * size) +
    (target.match?(INLINE_OPEN_BLOCK_MATCHER) ? INLINE_CLOSE_BLOCK : CLOSE_BLOCK)
  ending   = starting + index(
    content[starting..-CONTENT_OFFSET],
    path,
    closing
  )

  content.slice!(starting..ending)
  write(path, content)

  remove_block(path, target) if match?(content, target)
end

#remove_line(path, target) ⇒ Object

Removes line from ‘path`, matching `target`.

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target to remove

Raises:

Since:

  • 0.1.0



779
780
781
782
783
784
785
# File 'lib/staticky/files.rb', line 779

def remove_line(path, target)
  content = adapter.readlines(path)
  i       = index(content, path, target)

  content.delete_at(i)
  write(path, content)
end

#replace_first_line(path, target, replacement) ⇒ Object

Replace first line in ‘path` that contains `target` with `replacement`.

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target to replace

  • replacement (String)

    the replacement

Raises:

See Also:

Since:

  • 0.1.0



340
341
342
343
344
345
# File 'lib/staticky/files.rb', line 340

def replace_first_line(path, target, replacement)
  content = adapter.readlines(path)
  content[index(content, path, target)] = newline(replacement)

  write(path, content)
end

#replace_last_line(path, target, replacement) ⇒ Object

Replace last line in ‘path` that contains `target` with `replacement`.

Parameters:

  • path (String, Pathname)

    the path to file

  • target (String, Regexp)

    the target to replace

  • replacement (String)

    the replacement

Raises:

See Also:

Since:

  • 0.1.0



360
361
362
363
364
365
366
# File 'lib/staticky/files.rb', line 360

def replace_last_line(path, target, replacement)
  content = adapter.readlines(path)
  content[-index(content.reverse, path, target) - CONTENT_OFFSET] =
    newline(replacement)

  write(path, content)
end

#touch(path) ⇒ Object

Creates an empty file for the given path. All the intermediate directories are created. If the path already exists, it doesn’t change the contents

Parameters:

  • path (String, Pathname)

    the path to file

Raises:



43
44
45
# File 'lib/staticky/files.rb', line 43

def touch(path)
  adapter.touch(path)
end

#unshift(path, line) ⇒ Object

Adds a new line at the top of the file

Parameters:

  • path (String, Pathname)

    the path to file

  • line (String)

    the line to add

Raises:

See Also:

Since:

  • 0.1.0



298
299
300
301
302
303
# File 'lib/staticky/files.rb', line 298

def unshift(path, line)
  content = adapter.readlines(path)
  content.unshift(newline(line))

  write(path, content)
end

#write(path, *content) ⇒ Object

Creates a new file or rewrites the contents of an existing file for the given path and content All the intermediate directories are created.

Parameters:

  • path (String, Pathname)

    the path to file

  • content (String, Array<String>)

    the content to write

Raises:



55
56
57
# File 'lib/staticky/files.rb', line 55

def write(path, *content)
  adapter.write(path, *content)
end