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

args(*names) click to toggle source

Public: Defines unaccessible arguments.

# File lib/perfume/super_object.rb, line 47
def self.args(*names)
  init_args.concat(names)
end
args_accessor(*names) click to toggle source

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
args_reader(*names) click to toggle source

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
args_writer(*names) click to toggle source

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
init_args() click to toggle source

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
new(args = {}) click to toggle source
# 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

defaults() click to toggle source

Public: Override it with your own default arguments.

# File lib/perfume/super_object.rb, line 84
def defaults
  {}
end
init() click to toggle source

Public: Extra initialization.

# File lib/perfume/super_object.rb, line 80
def init
end