Created
October 13, 2016 17:08
-
-
Save sczizzo/d1fb18b690ed52425a740b35fe7a8dc8 to your computer and use it in GitHub Desktop.
Have some respect, and show some class!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Classy | |
module Errors | |
def self.included(base) | |
base.extend(ClassMethods.clone) | |
base.private_class_method :error | |
end | |
module ClassMethods | |
def error(name, super_klass = StandardError) | |
klass_name = name.to_s.split('_').map(&:capitalize).join | |
klass = Class.new(super_klass) | |
const_set "#{klass_name}Error", klass | |
end | |
end | |
private | |
def error!(name) | |
klass_name = name.to_s.split('_').map(&:capitalize).join | |
raise self.class.const_get("#{klass_name}Error") | |
end | |
end | |
module Builder | |
def self.included(base) | |
base.extend(ClassMethods.clone) | |
base.private_class_method :builder | |
end | |
module ClassMethods | |
DEFAULT_BUILDER_OPTIONS = { | |
set_instance_variables?: true | |
}.freeze | |
def builder(options = DEFAULT_BUILDER_OPTIONS, &block) | |
@@opt_args = [] | |
@@rest_args = [] | |
@@block_args = [] | |
@@klass = Class.new(Object) | |
block.parameters.each do |kind, arg| | |
case kind | |
when :opt | |
@@opt_args << arg | |
@@klass.send :define_method, arg.to_s do |opt| | |
instance_variable_set "@#{arg}", opt | |
end | |
when :rest | |
@@rest_args << arg | |
@@klass.send :define_method, arg.to_s do |*rest| | |
instance_variable_set "@#{arg}", rest | |
end | |
when :block | |
@@block_args << arg | |
@@klass.send :define_method, arg.to_s do |&bblock| | |
instance_variable_set "@#{arg}", bblock | |
end | |
end | |
end | |
if options[:set_instance_variables?] | |
define_method :initialize do |*new_args, &new_block| | |
opts = @@opt_args.map { |oa| [oa, new_args.shift] } | |
rests = @@rest_args.map { |ra| [ra, new_args] } | |
blocks = @@block_args.map { |ba| [ba, new_block] } | |
(opts + rests + blocks).each do |name, val| | |
instance_variable_set "@#{name}", val | |
end | |
block_args = opts.map(&:last) | |
rests.map(&:last).each { |rest| block_args += rest } | |
instance_exec(*block_args, &block) | |
end | |
else | |
define_method :initialize, &block | |
end | |
end | |
def build(&block) | |
builder = @@klass.new | |
builder.instance_eval(&block) if block_given? | |
args = @@opt_args.map do |arg| | |
builder.instance_variable_get "@#{arg}" | |
end | |
if rest_arg = @@rest_args.first | |
ra = builder.instance_variable_get("@#{rest_arg}") | |
args += ra if ra | |
end | |
if block_arg = @@block_args.first | |
ba = builder.instance_variable_get("@#{block_arg}") | |
new(*args, &ba) | |
else | |
new(*args) | |
end | |
end | |
end | |
end | |
end | |
class Message | |
include Classy::Errors | |
include Classy::Builder | |
error :bad_subject | |
error :no_subject | |
error :no_body | |
attr_reader :subject, :body, :args | |
builder do |subject, body, *args, &delivery| | |
error! :no_subject unless @subject | |
error! :bad_subject unless @subject =~ /awesome/i | |
error! :no_body unless @body | |
end | |
def deliver | |
instance_eval(&@delivery) if @delivery | |
end | |
end | |
class AutoDeliveredMessage < Message | |
def initialize(*as) | |
super(*as) | |
deliver | |
end | |
end | |
require 'json' | |
m1 = Message.build do | |
subject 'testy awesome test' | |
body 'ya boi' | |
end | |
m2 = Message.build do | |
subject 'aight but awesome' | |
body 'ya boi' | |
args 'one', 'two', 'three' | |
delivery do | |
puts JSON.pretty_generate( | |
kind: :message, | |
subject: subject, | |
body: body, | |
args: args | |
) | |
end | |
end | |
m3 = Message.new('not awesome', 'but works', 'test', 'test', 'test') do | |
puts JSON.pretty_generate( | |
kind: :message, | |
subject: subject, | |
body: body, | |
args: args | |
) | |
end | |
m1.deliver | |
m2.deliver | |
m3.deliver | |
AutoDeliveredMessage.build do | |
subject 'pretty awesome' | |
body 'and works' | |
delivery do | |
puts JSON.pretty_generate( | |
kind: :message, | |
subject: subject, | |
body: body, | |
args: args | |
) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment