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.2.1"

Instance Method Summary collapse

Constructor Details

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

Creates a new instance

Memory file system is experimental



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

Raises:

See Also:

Since:

  • 0.1.0



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

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) ⇒ Object

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

Raises:



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

def chdir(path, &)
  adapter.chdir(path, &)
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.

Raises:



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

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.

Raises:

Since:

  • 0.1.0



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

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

#delete(path) ⇒ Object

Deletes given path (file).

Raises:

Since:

  • 0.1.0



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

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

#delete_directory(path) ⇒ Object

Deletes given path (directory).

Raises:

Since:

  • 0.1.0



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

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

Since:

  • 0.1.0



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

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

#entries(path) ⇒ Object

Reads entries from a directory

Raises:

Since:

  • 0.1.0



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

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

Since:

  • 0.1.0



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

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

Since:

  • 0.1.0



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

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.



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

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

#glob(pattern) ⇒ Object

Reads files matching the given glob pattern

Since:

  • 0.1.0



853
854
855
# File 'lib/staticky/files.rb', line 853

def glob(pattern)
  adapter.glob(pattern)
end

#inject_line_after(path, target, contents) ⇒ Object

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

Raises:

See Also:

Since:

  • 0.1.0



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

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`.

Raises:

See Also:

Since:

  • 0.1.0



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

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 = "settings do\n  load!\nend\n"
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

Raises:

Since:

  • 0.1.0



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

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 = "settings do\n  load!\nend\n"
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

Raises:

Since:

  • 0.1.0



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

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

Raises:

Since:

  • 0.4.0



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

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`.

Raises:

See Also:

Since:

  • 0.1.0



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

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`.

Raises:

See Also:

Since:

  • 0.1.0



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

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



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

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

Raises:

See Also:

Since:

  • 0.1.0



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

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

Raises:

See Also:

Since:

  • 0.1.0



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

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

Yield Parameters:

Raises:



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

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

#pwdString

Returns the name of the current working directory.



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

def pwd
  adapter.pwd
end

#read(path) ⇒ String

Read file content

TODO: allow buffered read

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

Raises:

Since:

  • 0.1.0



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

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`.

Raises:

Since:

  • 0.1.0



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

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`.

Raises:

See Also:

Since:

  • 0.1.0



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

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`.

Raises:

See Also:

Since:

  • 0.1.0



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

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

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

Raises:

See Also:

Since:

  • 0.1.0



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

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.

Raises:



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

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