File: has_directives.rb

package info (click to toggle)
ruby-graphql 2.2.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,584 kB
  • sloc: ruby: 67,505; ansic: 1,753; yacc: 831; javascript: 331; makefile: 6
file content (118 lines) | stat: -rw-r--r-- 4,083 bytes parent folder | download
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
115
116
117
118
# frozen_string_literal: true

module GraphQL
  class Schema
    class Member
      module HasDirectives
        def self.extended(child_cls)
          super
          child_cls.module_exec { self.own_directives = nil }
        end

        def inherited(child_cls)
          super
          child_cls.own_directives = nil
        end

        # Create an instance of `dir_class` for `self`, using `options`.
        #
        # It removes a previously-attached instance of `dir_class`, if there is one.
        #
        # @return [void]
        def directive(dir_class, **options)
          @own_directives ||= []
          HasDirectives.add_directive(self, @own_directives, dir_class, options)
          nil
        end

        # Remove an attached instance of `dir_class`, if there is one
        # @param dir_class [Class<GraphQL::Schema::Directive>]
        # @return [viod]
        def remove_directive(dir_class)
          HasDirectives.remove_directive(@own_directives, dir_class)
          nil
        end

        def directives
          HasDirectives.get_directives(self, @own_directives, :directives)
        end

        class << self
          def add_directive(schema_member, directives, directive_class, directive_options)
            remove_directive(directives, directive_class) unless directive_class.repeatable?
            directives << directive_class.new(schema_member, **directive_options)
          end

          def remove_directive(directives, directive_class)
            directives && directives.reject! { |d| d.is_a?(directive_class) }
          end

          def get_directives(schema_member, directives, directives_method)
            case schema_member
            when Class
              inherited_directives = if schema_member.superclass.respond_to?(directives_method)
                get_directives(schema_member.superclass, schema_member.superclass.public_send(directives_method), directives_method)
              else
                GraphQL::EmptyObjects::EMPTY_ARRAY
              end
              if inherited_directives.any? && directives
                dirs = []
                merge_directives(dirs, inherited_directives)
                merge_directives(dirs, directives)
                dirs
              elsif directives
                directives
              elsif inherited_directives.any?
                inherited_directives
              else
                GraphQL::EmptyObjects::EMPTY_ARRAY
              end
            when Module
              dirs = nil
              schema_member.ancestors.reverse_each do |ancestor|
                if ancestor.respond_to?(:own_directives) &&
                    (anc_dirs = ancestor.own_directives).any?
                  dirs ||= []
                  merge_directives(dirs, anc_dirs)
                end
              end
              if directives
                dirs ||= []
                merge_directives(dirs, directives)
              end
              dirs || GraphQL::EmptyObjects::EMPTY_ARRAY
            when HasDirectives
              directives || GraphQL::EmptyObjects::EMPTY_ARRAY
            else
              raise "Invariant: how could #{schema_member} not be a Class, Module, or instance of HasDirectives?"
            end
          end

          private

          # Modify `target` by adding items from `dirs` such that:
          # - Any name conflict is overriden by the incoming member of `dirs`
          # - Any other member of `dirs` is appended
          # @param target [Array<GraphQL::Schema::Directive>]
          # @param dirs [Array<GraphQL::Schema::Directive>]
          # @return [void]
          def merge_directives(target, dirs)
            dirs.each do |dir|
              if (idx = target.find_index { |d| d.graphql_name == dir.graphql_name })
                target.slice!(idx)
                target.insert(idx, dir)
              else
                target << dir
              end
            end
            nil
          end
        end

        protected

        attr_accessor :own_directives
      end
    end
  end
end