1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
# frozen_string_literal: true
module Unparser
# A mixin to define a composition
#
# Original code before vendoring and reduction from: https://github.com/mbj/concord.
class Concord < Module
include Adamantium, Equalizer.new(:names)
# The maximum number of objects the hosting class is composed of
MAX_NR_OF_OBJECTS = 3
# Return names
#
# @return [Enumerable<Symbol>]
#
# @api private
#
attr_reader :names
private
# Initialize object
#
# @return [undefined]
#
# @api private
#
# rubocop:disable Lint/MissingSuper
def initialize(*names)
if names.length > MAX_NR_OF_OBJECTS
fail "Composition of more than #{MAX_NR_OF_OBJECTS} objects is not allowed"
end
@names = names
define_initialize
define_readers
define_equalizer
end
# rubocop:enable Lint/MissingSuper
# Define equalizer
#
# @return [undefined]
#
# @api private
#
def define_equalizer
include(Equalizer.new(*names))
end
# Define readers
#
# @return [undefined]
#
# @api private
#
def define_readers
attribute_names = names
attr_reader(*attribute_names)
protected(*attribute_names) if attribute_names.any?
end
# Define initialize method
#
# @return [undefined]
#
# @api private
#
#
def define_initialize
ivars = instance_variable_names
size = names.size
define_method :initialize do |*args|
args_size = args.size
unless args_size.equal?(size)
fail ArgumentError, "wrong number of arguments (#{args_size} for #{size})"
end
ivars.zip(args) { |ivar, arg| instance_variable_set(ivar, arg) }
end
end
# Return instance variable names
#
# @return [String]
#
# @api private
#
def instance_variable_names
names.map { |name| "@#{name}" }
end
# Mixin for public attribute readers
class Public < self
# Hook called when module is included
#
# @param [Class,Module] descendant
#
# @return [undefined]
#
# @api private
#
def included(descendant)
names.each do |name|
descendant.__send__(:public, name)
end
end
end # Public
end # Concord
end # Unparser
|