Last active
December 18, 2015 13:09
-
-
Save saturnflyer/5788041 to your computer and use it in GitHub Desktop.
This is a class methods that allows you to simplify the setup of arguments, objects, and methods.
This file contains 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
class Something | |
setup(:first, :second) | |
module Second | |
end | |
end | |
# This is the equivalent of what the code above does... | |
class Something | |
def initialize(first, second) | |
@first, @second = first, second.extend(Second) | |
end | |
attr_reader :first, :second | |
private: :first, second | |
module Second | |
end | |
end | |
# implementation of the setup method | |
class Something | |
def setup(*setup_args) | |
attr_reader(*setup_args) | |
private(*setup_args) | |
define_method(:initialize){ |*args| | |
Hash[setup_args.zip(args)].each{ |role, object| | |
role_module_name = role.classify # from active support | |
klass = self.class | |
if mod = klass.const_defined?(role_module_name) && !mod.is_a?(Class) | |
object = object.extend(klass.const_get(role_module_name)) | |
end | |
instance_variable_set("@#{role}", object) | |
} | |
} | |
end | |
end |
Not completely happy, but it's easier for me to understand at a glance. Also, the new class methods can be easily re-used.
class Something
private_attr_reader :roles
def self.setup(*roles)
@roles = roles.dup.freeze
private_attr_reader *roles
define_method(:initialize) do |*args|
raise ArgumentError.new 'roles size differs' if args.size > roles.size
roles.zip(args).each do |role, object|
object.extend(get_role_module role) if has_role_module? role
instance_variable_set("@#{role}", object)
end
end
end
def self.private_attr_reader(*attributes)
attr_reader(*attributes)
private(*attributes)
end
def self.has_role_module?(role)
roles.include?(role) && self.class.const_defined?(role.classify) # from active support
end
def self.get_role_module(role)
self.class.const_get role.classify
end
end
Original line 34 (see next line) attempted to check if the module existed:
if mod = klass.const_defined?(role_module_name) && !mod.is_a?(Class)
However, mod
would only ever be a boolean based on const_defined?
being a predicate. So !mod.is_a?(Class)
would always be true
, as mod
would either of been true
or false
. In my version, I didn't do the check in either has_role_module?
or get_role_module
.
Mostly because I was being lazy; partly because I wanted to emphasize the refactor, and not bullet proof the code.
Ah. Good catch with the is_a?
call on a false object.
I'm thinking about this stuff and reworking things.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The
Hash[]
on line 29 is sort of pointless. I understand you're trying to show that you're mapping the role name to the object, but it does nothing for your code. You never use it and since this is theinitialize
method, it will never get returned: