diff options
author | Simon Parri <simonparri@ganzeria.com> | 2025-06-10 22:40:46 -0500 |
---|---|---|
committer | Simon Parri <simonparri@ganzeria.com> | 2025-06-10 22:40:46 -0500 |
commit | d7661d34cd16cfc536631cf606a120b7c6d3053c (patch) | |
tree | c7fd1798fc6540a0f36bc7d2ef4b64e78c3078aa /core.rb | |
download | dotdot-d7661d34cd16cfc536631cf606a120b7c6d3053c.tar.gz dotdot-d7661d34cd16cfc536631cf606a120b7c6d3053c.zip |
Add initial version
Diffstat (limited to 'core.rb')
-rw-r--r-- | core.rb | 85 |
1 files changed, 85 insertions, 0 deletions
@@ -0,0 +1,85 @@ +class Op + def check + raise "#{self.class} doesn't have a (required) 'check' method" + end + def do + raise "#{self.class} doesn't have a (required) 'do' method" + end + def undo + raise "#{self.class} doesn't have a (required) 'undo' method" + end +end + +def defop(name, args, &block) + name = name.to_sym + eval "class #{name} < Op; end" # Must use `eval' to access + cls = eval "#{name}" # the global namespace + cls.instance_eval do + args.map {|a| attr_reader a.to_sym } + end + cls.define_method :initialize do |**kwargs| + args.each {|arg| instance_variable_set :"@#{arg}", kwargs[arg.to_sym] } + end + cls.define_method :to_s do inspect end + cls.define_method :to_str do to_s end + cls.instance_eval &block +end + +defop :Write, [:file, :contents] do + define_method :check do + if File.exist? @file + if (File.read @file) != @contents + raise "File `#{@file}' exists but has unexpected contents" + else true + end + end + end + define_method :do do + write @file, @contents + end + define_method :undo do + rm @file + end +end + +defop :Deploy, [:ops, :save] do + define_method :initialize do |save: nil, &block| + @ops = [] + @save = save + self.instance_eval &block + end + define_method :check do + @ops.all? {|op| op.check } and + (@save ? self.save.check : true) + end + define_method :do do + self.load.undo if @save && self.save.check + @ops.each {|op| op.check || op.do } + self.save.do if @save + end + define_method :undo do + @ops.reverse.each {|op| op.check && op.undo } + self.save.undo if @save + end + define_method :save do + (Write.new file: @save, + contents: self.to_yaml) + end + define_method :load do + YAML.load_file( + @save, + permitted_classes: ([Op] + Op.subclasses)) + end +end + +def deploy(...) + Deploy.new(...) +end + +def defdeploy(name, &block) + Deploy.define_method name, &block +end + +defdeploy :op do |cls, **args| + @ops.push cls.new(**args) +end |