~singpolyma/dhall-ruby

7f636a8e64f190fbca72ae31abb34f72632b57ea — Stephen Paul Weber 3 years ago d78e183
Allow as_dhall to be customised by encode_with

Dhall has a goal to replace YAML.  Ruby's ecosystem already has deep
integration with YAML (specifically with the Psych implementation in
stdlib) -- so if an object customises its YAML encoding, but doesn't
know about Dhall, customise the Dhall encoding in a compatible way.
2 files changed, 31 insertions(+), 6 deletions(-)

M lib/dhall/as_dhall.rb
M lib/dhall/util.rb
M lib/dhall/as_dhall.rb => lib/dhall/as_dhall.rb +17 -6
@@ 1,6 1,7 @@
# frozen_string_literal: true

require "ostruct"
require "psych"

module Dhall
	module AsDhall


@@ 189,18 190,28 @@ module Dhall
			end
		end

		refine ::Object do
		refine ::Psych::Coder do
			def as_dhall
				ivars = instance_variables.each_with_object({}) { |ivar, h|
					h[ivar.to_s[1..-1]] = instance_variable_get(ivar)
				}.as_dhall
				case type
				when :seq
					seq
				when :map
					map
				else
					scalar
				end.as_dhall
			end
		end

				type = TypeChecker.for(ivars).annotate(TypeChecker::Context.new).type
		refine ::Object do
			def as_dhall
				tag = self.class.name
				expr = Util.psych_coder_from(tag, self).as_dhall
				type = TypeChecker.for(expr).annotate(TypeChecker::Context.new).type
				Union.from(
					UnionType.new(alternatives: { tag => type }),
					tag,
					ivars
					expr
				)
			end
		end

M lib/dhall/util.rb => lib/dhall/util.rb +14 -0
@@ 84,5 84,19 @@ module Dhall
				end]
			end
		end

		def self.psych_coder_from(tag, o)
			coder = Psych::Coder.new(tag)

			if o.respond_to?(:encode_with)
				o.encode_with(coder)
			else
				o.instance_variables.each do |ivar|
					coder[ivar.to_s[1..-1]] = o.instance_variable_get(ivar)
				end
			end

			coder
		end
	end
end