Skip to content

Instantly share code, notes, and snippets.

@seeker815
Forked from sczizzo/chef_dsl.rb
Created May 3, 2016 16:13
Show Gist options
  • Save seeker815/68debcf9774959c34f393a58a011fa3c to your computer and use it in GitHub Desktop.
Save seeker815/68debcf9774959c34f393a58a011fa3c to your computer and use it in GitHub Desktop.
How one might implement Chef's Recipe DSL
# Basics
module Chef
class Resource
attr_reader :name
def initialize name
@name = name
end
def execute
raise 'To be implemented by subclass...'
end
end
end
module Chef
class Recipe
attr_reader :resources
def initialize resources
@resources = resources
@executed = false
end
def execute
return if @executed
@executed = true
@resources.each(&:execute)
end
end
end
# Builders
module Chef
class Resource
class Builder
attr_reader :resource
def camelize s
s.to_s.split('_').map(&:capitalize).join('')
end
def initialize kind, name, &block
klass = Chef::Resource.const_get camelize(kind)
@resource = klass.new name
@resource.instance_eval &block if block
end
end
end
end
module Chef
class Recipe
class Builder
attr_reader :recipe
def initialize &block
@resources = []
instance_eval &block if block
@recipe = Chef::Recipe.new @resources
end
def method_missing resource, *args, &block
@resources << Chef::Resource::Builder.new(resource, *args, &block).resource
rescue NameError
super
end
end
end
end
module Chef
def self.recipe &block
Chef::Recipe::Builder.new(&block).recipe.execute
end
end
# Resources
module Chef
class Resource
class Log < Resource
require 'date'
require 'time'
def initialize name
super name
@level = 'INFO'
@precision = 3
end
def level l
@level = l
end
def precision n
@precision = n
end
def now
Time.now.utc.iso8601(@precision)
end
def execute
puts '%s [%s] %s' % [ @level, now, @name ]
end
end
end
end
module Chef
class Resource
class File < Resource
require 'fileutils'
require 'date'
require 'time'
def action a
@action = a
end
def contents s
@contents = s
end
def execute
@action ||= :create
case @action
when :create
::File.open(@name, 'w') { |f| f.puts @contents }
puts 'Wrote file at %s' % @name.inspect
when :delete
::FileUtils.rm_rf @name
puts 'Deleted file at %s' % @name.inspect
else
raise 'Invalid action provided for file resource'
end
end
end
end
end
module Chef
class Resource
class RubyBlock < Resource
def block &block
@block = block
end
def execute
@block.call if @block
end
end
end
end
# Using the DSL...
Chef.recipe do
log 'hello, world!'
file '/tmp/foo' do
contents 'test'
end
ruby_block 'read_file' do
puts 'inside the ruby_block, but outside the block itself'
block do
contents = File.read('/tmp/foo')
puts "Read file: %s" % contents.inspect
end
end
file '/tmp/foo' do
action :delete
end
log 'goodbye, world!' do
level 'DEBUG'
precision 6
end
puts inspect
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment