Skip to content

Instantly share code, notes, and snippets.

@coreyti
Last active September 11, 2020 18:24
Show Gist options
  • Save coreyti/17dda3c996d9d188bf72feb41e678290 to your computer and use it in GitHub Desktop.
Save coreyti/17dda3c996d9d188bf72feb41e678290 to your computer and use it in GitHub Desktop.
Command to render ERB+YAML
#!/usr/bin/env ruby
require 'optparse'
require 'ostruct'
require 'erb'
require 'json'
require 'yaml'
module GCP
class Context
def self.for(path, params)
self.new(path, params).send(:__binding__)
end
def initialize(path, params)
file = File.read(path) if path && File.exist?(path)
@data = file.nil? ? {} : YAML.load(file)
@path = path
@params = params
end
def data
@_data ||= to_ostruct(@data)
end
def env
@env ||= to_ostruct(ENV)
end
def render(path, options = {})
full = File.expand_path(File.join(@params[:template], '..', path))
file = File.read(full)
data = YAML.load(::ERB.new(file).result(self.send(:__binding__)))
data.to_json
end
private
def to_ostruct(hash)
result = OpenStruct.new(hash)
hash.each.with_object(result) do |(key, value), result|
result.send(:"#{key}=", to_ostruct(value)) if value.is_a?(Hash)
end
result
end
def __binding__
binding.taint
end
end
class Template
def initialize(path)
@file = File.read(path)
end
def render(context)
::ERB.new(@file).result(context)
end
end
class Arguments < Struct.new(:tmpl, :data)
def valid?
File.exist?(tmpl) && (data.nil? || File.exist?(data))
end
end
class Parser
def self.parse(options)
args = Arguments.new
input = OptionParser.new do |opts|
opts.banner = "Usage: render [options]"
opts.on '-t', '--tmpl=<path>', "[required] A path to ERB template" do |value|
args.tmpl = value
end
opts.on '-d', '--data=<path>', "[optional] A path to YAML data" do |value|
args.data = value
end
opts.on_tail '-h', '--help', "Prints this help" do |value|
puts opts ; exit
end
end
input.parse!(options)
if args.valid?
return args
else
puts input.help ; exit 1
end
end
end
end
arguments = GCP::Parser.parse(ARGV)
template = GCP::Template.new arguments.tmpl
context = GCP::Context.for arguments.data, template: arguments.tmpl
puts template.render(context)
---
something:
nested: has a value
---
key: <%= data.something.nested %>
---
# render this as:
# `VARIABLE=value ./render -t example-tmpl.yml -d example-data.yml`
thing: <%= data.something.nested %>
other: <%= env.VARIABLE %>
partial: <%= render('example-part.yml') %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment