Module: Rails::GraphQL::Helpers::InheritedCollection

Included in:
Source
Defined in:
lib/rails/graphql/helpers/inherited_collection.rb

Overview

Helper module that allow classes to have specific type of attributes that are corretly delt when it is inherited by another class. It keeps track of its own value and allow access to all values of the property in the tree,

TODO: Rewrite this!

Defined Under Namespace

Classes: Array, Base, Hash

Constant Summary collapse

DEFAULT_TYPES =

All possible types of inheritable values

{
  array:      '[]',
  set:        'Set.new',
  hash:       '{}',
  hash_array: '::Hash.new { |h, k| h[k] = [] }',
  hash_set:   '::Hash.new { |h, k| h[k] = Set.new }',
}.freeze

Instance Method Summary collapse

Instance Method Details

#inherited_collection(*attrs, instance_reader: true, instance_predicate: true, type: :set) ⇒ Object

Declare a class-level attribute whose value is both isolated and also inherited from parent classes. Subclasses can change their own value and it will not impact parent class.

Inspired by class_attribute from ActiveSupport.

Options

  • :instance_reader - Sets the instance reader method (defaults to true).

  • :instance_predicate - Sets a predicate method (defaults to true).

  • :type - Defines the type of the values stored (defaults to :set).

Examples

class Base
  inherited_collection :settings
end

class Subclass < Base
end

Base.settings << :a
Subclass.settings            # => []
Subclass.all_settings        # => [:a]
Subclass.settings << :b
Subclass.settings            # => [:b]
Subclass.all_settings        # => [:a, :b]
Base.settings                # => [:a]
Base.all_settings            # => [:a]

For convenience, an instance predicate method is defined as well, which checks for the all_ method. To skip it, pass instance_predicate: false.

Subclass.settings?       # => false

To opt out of the instance reader method, pass instance_reader: false.

object.settings          # => NoMethodError
object.settings?         # => NoMethodError


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
# File 'lib/rails/graphql/helpers/inherited_collection.rb', line 63

def inherited_collection(
  *attrs,
  instance_reader: true,
  instance_predicate: true,
  type: :set
)
  attrs.each do |name|
    instance_eval(<<~RUBY, __FILE__, __LINE__ + 1)
      def all_#{name}
        return superclass.try(:all_#{name}) unless defined?(@#{name})
        InheritedCollection::Base.handle(self, :@#{name}, :#{type})
      end

      def #{name}
        @#{name} ||= #{DEFAULT_TYPES[type]}
      end
    RUBY

    instance_eval(<<~RUBY, __FILE__, __LINE__ + 1) if instance_predicate
      def #{name}?
        (defined?(@#{name}) && @#{name}.present?) || superclass.try(:#{name}?)
      end
    RUBY

    if instance_reader
      delegate(name.to_sym, :"all_#{name}", to: :class)
      delegate(:"#{name}?", to: :class) if instance_predicate
    end
  end
end