Skip to content

Instantly share code, notes, and snippets.

@plexus
Created October 29, 2014 16:08
Show Gist options
  • Save plexus/864c04f50bc046d65f6d to your computer and use it in GitHub Desktop.
Save plexus/864c04f50bc046d65f6d to your computer and use it in GitHub Desktop.
module Yaks
# State monad-ish thing.
#
# Generate a DSL syntax for immutable classes.
#
# @example
#
# # This code
# Control.create(:search)
# .method("POST")
# .href("/search")
#
# # Can be written as
# StatefulBuilder.new(Control, [:method, :href]).create(:search) do
# method "POST"
# href "/search"
# end
#
class StatefulBuilder < BasicObject
def create(*args, &block)
@state = @klass.create(*args)
instance_eval(&block)
@state
end
def initialize(klass, methods)
@klass = klass
StatefulMethods.new(methods).send(:extend_object, self)
end
def validate_state(method_name, args)
unless @state.is_a?(@klass)
::Kernel.raise(
::Yaks::IllegalState,
"#{@klass}##{method_name}(#{args.map(&:inspect).join(', ')}) "\
"returned #{@state.inspect}. Expected instance of #{@klass}"
)
end
end
class StatefulMethods < ::Module
def initialize(methods)
methods.each { |name| define_stateful_method(name) }
end
def define_stateful_method(method_name)
define_method method_name do |*args, &block|
@state = @state.public_send(method_name, *args, &block)
validate_state(method_name, args)
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment