Class: Fned::Rename

Inherits:
Object
  • Object
show all
Defined in:
lib/fned/rename.rb

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Rename

Returns a new instance of Rename.



19
20
21
22
23
24
25
# File 'lib/fned/rename.rb', line 19

def initialize(options = {})
  @options = {
    :verbose => false,
  }.merge(options)

  @renames = {}
end

Instance Method Details

#add(source, destination) ⇒ Object

add source, destination to list of intended renames



32
33
34
# File 'lib/fned/rename.rb', line 32

def add(source, destination)
  @renames[source] = destination
end

#normalize(path) ⇒ Object

normalize path



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/fned/rename.rb', line 52

def normalize(path)
  # NOTE: removing /../ by removing the previous component of a path
  # is a bad idea as /symlink/../ is the parent directory of the
  # directory the symlink is pointing to, which is in general not
  # the same as /.
  path.to_s.
    # replace successive slashes
    gsub(%r{//+}, "/").
    # remove trailing slash
    sub(%r{/\z}, "").
    # replace /./
    gsub(%r{/\./}, "/").
    # remove ./ in the beginning and /. in the end
    gsub(%r{(?:\A\./|/\.\z)}, "")
end

#rename(source, destination) ⇒ Object

rename a single file



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/fned/rename.rb', line 69

def rename(source, destination)
  # Normalizing the paths has two reasons:
  # (1) renaming symlinks fails with trailing slashes but trailing
  #     slashes might be present if the symlink points to a directory
  # (2) comparison if source and destination are the same
  src, dst = normalize(source), normalize(destination)

  return if src == dst

  # TODO: racy, use link(src, dst); unlink(src)?
  if File.exist?(dst)
    warn "not renaming because target exists: %s -> %s" %
    [source.to_s.inspect, destination.to_s.inspect]
    return
  end

  begin
    # TODO: add cross filesystem rename
    puts "%s -> %s" % [source.to_s.inspect, destination.to_s.inspect] if verbose?
    File.rename(src, dst)
  rescue SystemCallError => error
    @errors << error
    # create a new exception to get the clean error message without
    # a filename
    warn "cannot rename %s: %s" % [source.to_s.inspect,
      SystemCallError.new(error.errno).message]
  end
end

#rename_filesObject

rename the added files, return array of errors



37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/fned/rename.rb', line 37

def rename_files
  @errors = []
  # Rename in reverse order of source filename such that directories
  # will be renamed after all files within the directory have been
  # renamed.
  # TODO: implement more advanced strategies for renaming
  # dependencies including cyclic dependencies (i.e. swapping
  # filenames)
  @renames.sort_by { |src, dst| src }.reverse.each do |src, dst|
    rename(src, dst)
  end
  @errors
end

#verbose?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/fned/rename.rb', line 27

def verbose?
  @options[:verbose]
end