File: base.rb

package info (click to toggle)
ruby-grape-entity 1.0.1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 456 kB
  • sloc: ruby: 3,335; makefile: 6
file content (141 lines) | stat: -rw-r--r-- 4,006 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# frozen_string_literal: true

require 'active_support'
require 'active_support/core_ext'

require 'active_support'
require 'active_support/core_ext'

module Grape
  class Entity
    module Exposure
      class Base
        attr_reader :attribute, :is_safe, :documentation, :override, :conditions, :for_merge

        def self.new(attribute, options, conditions, ...)
          super(attribute, options, conditions).tap { |e| e.setup(...) }
        end

        def initialize(attribute, options, conditions)
          @attribute = attribute.try(:to_sym)
          @options = options
          key = options[:as] || attribute
          @key = key.respond_to?(:to_sym) ? key.to_sym : key
          @is_safe = options[:safe]
          @default_value = options[:default]
          @for_merge = options[:merge]
          @attr_path_proc = options[:attr_path]
          @documentation = options[:documentation]
          @override = options[:override]
          @conditions = conditions
        end

        def dup(&block)
          self.class.new(*dup_args, &block)
        end

        def dup_args
          [@attribute, @options, @conditions.map(&:dup)]
        end

        def ==(other)
          self.class == other.class &&
            @attribute == other.attribute &&
            @options == other.options &&
            @conditions == other.conditions
        end

        def setup; end

        def nesting?
          false
        end

        # if we have any nesting exposures with the same name.
        def deep_complex_nesting?(entity) # rubocop:disable Lint/UnusedMethodArgument
          false
        end

        def valid?(entity)
          is_delegatable = entity.delegator.delegatable?(@attribute) || entity.respond_to?(@attribute, true)
          if @is_safe
            is_delegatable
          else
            is_delegatable || raise(
              NoMethodError,
              "#{entity.class.name} missing attribute `#{@attribute}' on #{entity.object}"
            )
          end
        end

        def value(_entity, _options)
          raise NotImplementedError
        end

        def serializable_value(entity, options)
          partial_output = valid_value(entity, options)

          if partial_output.respond_to?(:serializable_hash)
            partial_output.serializable_hash
          elsif partial_output.is_a?(Array) && partial_output.all? { |o| o.respond_to?(:serializable_hash) }
            partial_output.map(&:serializable_hash)
          elsif partial_output.is_a?(Hash)
            partial_output.each do |key, value|
              partial_output[key] = value.serializable_hash if value.respond_to?(:serializable_hash)
            end
          else
            partial_output
          end
        end

        def valid_value(entity, options)
          return unless valid?(entity)

          output = value(entity, options)
          output.blank? && !@default_value.nil? ? @default_value : output
        end

        def should_return_key?(options)
          options.should_return_key?(@key)
        end

        def conditional?
          !@conditions.empty?
        end

        def conditions_met?(entity, options)
          @conditions.all? { |condition| condition.met? entity, options }
        end

        def should_expose?(entity, options)
          should_return_key?(options) && conditions_met?(entity, options)
        end

        def attr_path(entity, options)
          if @attr_path_proc
            entity.exec_with_object(options, &@attr_path_proc)
          else
            @key
          end
        end

        def key(entity = nil)
          @key.respond_to?(:call) ? entity.exec_with_object(@options, &@key) : @key
        end

        def with_attr_path(entity, options, &block)
          path_part = attr_path(entity, options)
          options.with_attr_path(path_part, &block)
        end

        def override?
          @override
        end

        protected

        attr_reader :options
      end
    end
  end
end