diff options
| -rw-r--r-- | lib/dslkeywords/directory.rb | 26 | ||||
| -rw-r--r-- | lib/dslkeywords/file.rb | 55 | ||||
| -rw-r--r-- | lib/dslkeywords/touch.rb | 4 |
3 files changed, 53 insertions, 32 deletions
diff --git a/lib/dslkeywords/directory.rb b/lib/dslkeywords/directory.rb index 402bead..6449d74 100644 --- a/lib/dslkeywords/directory.rb +++ b/lib/dslkeywords/directory.rb @@ -5,9 +5,15 @@ require_relative 'file' module RCM # Manages directories: create, delete/purge, or recursively copy from # a source directory. Backup is performed before destructive operations. - class Directory < BaseFile + # Extends BasicFile directly — Directory has no file content or sourcing, + # so it must not inherit content/from from BaseFile (ISP). The source + # directory for recursive copy is stored via the separate #source method. + class Directory < BasicFile def recursively = @recursively = true + # Set or get the source directory path used for recursive copy. + def source(path = nil) = path.nil? ? @source_path : @source_path = path + def evaluate! return unless super @@ -35,6 +41,8 @@ module RCM end end + # Override BasicFile#evaluate_absent! with directory-specific behaviour: + # optionally recursive removal and backup of the whole directory tree. def evaluate_absent! return unless ::File.directory?(@file_path) @@ -51,20 +59,20 @@ module RCM end def evaluate_present_recursively! - source_path = content - raise "Source #{source_path} is not a directory!" unless ::File.directory?(source_path) + src = source + raise "Source #{src} is not a directory!" unless ::File.directory?(src) if ::File.exist?(@file_path) raise "Destination #{@file_path} is not a directory!" unless ::File.directory?(@file_path) - backup_recursively!(source_path, @file_path) unless @without_backup + backup_recursively!(src, @file_path) unless @without_backup end - do? "Copying #{source_path} -> #{@file_path} recursively" do + do? "Copying #{src} -> #{@file_path} recursively" do if ::File.directory?(@file_path) - Dir["#{source_path}/*"].each { FileUtils.cp_r(_1, @file_path) } + Dir["#{src}/*"].each { FileUtils.cp_r(_1, @file_path) } else - FileUtils.cp_r(source_path, @file_path) + FileUtils.cp_r(src, @file_path) end end end @@ -96,7 +104,9 @@ module RCM return unless @conds_met d = Directory.new(file_path) - d.content(d.instance_eval(&block)) + # Use source= for the recursive-copy source path rather than content=, + # keeping Directory's interface clean and purpose-named. + d.source(d.instance_eval(&block)) self << d d end diff --git a/lib/dslkeywords/file.rb b/lib/dslkeywords/file.rb index 273968c..dc6f4d0 100644 --- a/lib/dslkeywords/file.rb +++ b/lib/dslkeywords/file.rb @@ -9,12 +9,18 @@ require_relative 'file_backup' module RCM # Base class shared by all file-system resources (files, symlinks, # touch, directories). Manages path, state (:present/:absent/:purged), - # permissions (mode/owner/group), parent-directory lifecycle, and the - # FileBackup mixin. + # permissions (mode/owner/group), and parent-directory lifecycle. + # Does NOT include content/templating — those belong in BaseFile so + # Touch and Directory (which have no file content) don't inherit them. class BasicFile < Resource include Chained include FileBackup + # Raised by validate when an unsupported DSL option is used. + # Defined here so BasicFile#validate can raise it even when the + # concrete class does not extend BaseFile. + class UnsupportedOperation < StandardError; end + def initialize(file_path) super(file_path) @file_path = file_path @@ -37,14 +43,6 @@ module RCM true end - def content(text = nil) - if text.nil? - text = @from == :sourcefile ? ::File.read(@content) : @content - return @from == :template ? ERB.new(text).result : text - end - @content = text.instance_of?(Array) ? text.join("\n") : text - end - protected def permissions!(file_path = path) @@ -63,6 +61,18 @@ module RCM "Unsupported '#{method}' operation #{what} (#{what.class})" end + # Delete the resource and optionally remove orphaned parent directories. + # Used by File, Symlink, and Touch; Directory overrides this. + def evaluate_absent! + if ::File.exist?(@file_path) + do? "Deleting #{@file_path}" do + backup!(@file_path) + ::File.delete(@file_path) if ::File.file?(@file_path) + end + end + cleanup_parent_directory! if @manage_directory + end + def create_parent_directory! dirname = ::File.dirname(@file_path) return if ::File.directory?(dirname) @@ -109,23 +119,22 @@ module RCM end end - # Intermediate base for resources that have file content and support - # :sourcefile / :template sourcing, and absent-state deletion. + # Intermediate base for resources that carry file content: regular files + # and symlinks. Adds content storage with optional ERB templating or + # sourcefile reading. Touch and Directory extend BasicFile directly so + # they are not burdened with content/from (ISP). class BaseFile < BasicFile - class UnsupportedOperation < StandardError; end - def from(what) = @from = validate(__method__, what.to_sym, :sourcefile, :template) - protected - - def evaluate_absent! - if ::File.exist?(@file_path) - do? "Deleting #{@file_path}" do - backup!(@file_path) - ::File.delete(@file_path) if ::File.file?(@file_path) - end + # Return or set the resource's content. + # Getter: resolves ERB templates or reads sourcefile on demand. + # Setter: stores plain text or joins an array with newlines. + def content(text = nil) + if text.nil? + text = @from == :sourcefile ? ::File.read(@content) : @content + return @from == :template ? ERB.new(text).result : text end - cleanup_parent_directory! if @manage_directory + @content = text.instance_of?(Array) ? text.join("\n") : text end end diff --git a/lib/dslkeywords/touch.rb b/lib/dslkeywords/touch.rb index d1073f2..27e691b 100644 --- a/lib/dslkeywords/touch.rb +++ b/lib/dslkeywords/touch.rb @@ -5,7 +5,9 @@ require_relative 'file' module RCM # Creates an empty file (touch semantics). Supports the additional # :updated state which re-touches the file even when it already exists. - class Touch < BaseFile + # Extends BasicFile directly — Touch has no file content or sourcing, + # so it must not inherit content/from from BaseFile (ISP). + class Touch < BasicFile def is(what) = @is = validate(__method__, what.to_sym, :present, :absent, :purged, :updated) def evaluate! |
