class Perfume::SuperObject
Public: Premise is tha using method arguments sucks because you need to remember the order, sucks even more when you might have lot of them (like structure/service initializers).
It’s often seen in ruby to declare classes that inherit from Struct. There we have problem of arguments order. Maybe I wanna specify defaults? Maybe I wanna pass only one argument from the middle of the list? For such cases people use OpenStruct or third-party stuff like Hashie::Dash. Not a good idea either because those classes are bloated with useless methods.
Here’s how this super object works:
class Women < SuperObject(:name, :surname) args :married def title @married ? 'Mrs.' : 'Miss' end def to_s [ title, name, surname ].join(' ') end end ada = Women.new(name: "Ada", surname: "Lovelace", married: true) ada.name # => "Ada" ada.surname # => "Lovelace" ada.to_s # => "Mrs. Ada Lovelace" mary = Women.new(name: "mary", surname: "Cassat", married: false) mary.to_s # => "Miss Mary Cassat" mary.married # => NoMethodError Women.new(unknown: 'Something') # => ArgumentError
By default ‘args` method defines only instance variables. Then we have `args_accessor`, which is called for all class parameters, `args_reader` and `args_writer` if you need to expose some stuff.
Public Class Methods
Public: Defines unaccessible arguments.
# File lib/perfume/super_object.rb, line 47 def self.args(*names) init_args.concat(names) end
Public: Defines given init arguments alongside with accessor methods.
# File lib/perfume/super_object.rb, line 52 def self.args_accessor(*names) names = names.map(&:to_sym) args(*names) attr_accessor(*names) end
Public: Defines given init arguments alongside with reader method.
# File lib/perfume/super_object.rb, line 59 def self.args_reader(*names) args(*names) attr_reader(*names) end
Public: Defines given init arguments alongside with writer method.
# File lib/perfume/super_object.rb, line 65 def self.args_writer(*names) args(*names) attr_writer(*names) end
Public: Returns list of defined arguments. Note that superclass arguments are inherited by child class.
# File lib/perfume/super_object.rb, line 42 def self.init_args @init_args ||= superclass.respond_to?(:init_args) ? superclass.init_args.dup : [] end
# File lib/perfume/super_object.rb, line 70 def initialize(args = {}) args.symbolize_keys! unknown_args = args.keys - self.class.init_args raise ArgumentError, "Unknown arguments: #{unknown_args.map(&:inspect).join(', ')}" unless unknown_args.empty? args = defaults.symbolize_keys.merge(args) self.class.init_args.each { |name| instance_variable_set("@#{name}", args[name]) } init end
Public Instance Methods
Public: Override it with your own default arguments.
# File lib/perfume/super_object.rb, line 84 def defaults {} end
Public: Extra initialization.
# File lib/perfume/super_object.rb, line 80 def init end