Class: Pakyow::Data::Proxy Private

Inherits:
Object
  • Object
show all
Includes:
Support::Inspectable
Defined in:
lib/pakyow/data/proxy.rb

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Constant Summary collapse

IVARS_TO_DUP =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%i(@proxied_calls @nested_proxies).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, subscribers, app) ⇒ Proxy

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Proxy.



22
23
24
25
26
27
28
# File 'lib/pakyow/data/proxy.rb', line 22

def initialize(source, subscribers, app)
  @source, @subscribers, @app = source, subscribers, app

  @proxied_calls = []
  @subscribable = true
  @nested_proxies = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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
# File 'lib/pakyow/data/proxy.rb', line 40

def method_missing(method_name, *args, &block)
  if @source.command?(method_name)
    dup.tap { |duped_proxy|
      result = @source.command(method_name).call(*args) { |yielded_result|
        duped_proxy.instance_variable_set(:@source, yielded_result)
        yield duped_proxy if block_given?
      }

      if @source.respond_to?(:transaction) && @source.transaction?
        @source.on_commit do
          @subscribers.did_mutate(
            @source.source_name, args[0], result
          )
        end
      else
        @subscribers.did_mutate(
          @source.source_name, args[0], result
        )
      end
    }
  elsif @source.query?(method_name) || @source.modifier?(method_name)
    dup.tap { |duped_proxy|
      nested_calls = []

      new_source = if block_given? && @source.block_for_nested_source?(method_name)
        # In this case a block has been passed that would, without intervention,
        # be called in context of a source instance. We don't want that, since
        # it would provide full access to the underlying dataset. Instead the
        # exposed object should simply be another proxy.

        local_subscribers, local_app = @subscribers, @app
        @source.source_from_self.public_send(method_name, *args) {
          nested_proxy = Proxy.new(self, local_subscribers, local_app)
          nested_proxy.instance_variable_set(:@proxied_calls, nested_calls)
          nested_proxy.instance_exec(&block).source.tap do |nested_proxy_source|
            duped_proxy.nested_proxies << nested_proxy.dup.tap do |finalized_nested_proxy|
              finalized_nested_proxy.instance_variable_set(:@source, nested_proxy_source)
            end
          end
        }
      else
        @source.source_from_self.public_send(method_name, *args).tap do |working_source|
          working_source.included.each do |_, included_source|
            nested_proxy = Proxy.new(included_source, @subscribers, @app)
            duped_proxy.nested_proxies << nested_proxy
          end
        end
      end

      duped_proxy.instance_variable_set(:@source, new_source)
      duped_proxy.instance_variable_get(:@proxied_calls) << [
        method_name, args, nested_calls
      ]
    }
  else
    if Array.instance_methods.include?(method_name) && !@source.class.instance_methods.include?(method_name)
      build_result(
        @source.to_a.public_send(method_name, *args, &block),
        method_name, args
      )
    elsif @source.class.instance_methods.include?(method_name)
      build_result(
        @source.public_send(method_name, *args, &block),
        method_name, args
      )
    else
      super
    end
  end
end

Instance Attribute Details

#appObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



20
21
22
# File 'lib/pakyow/data/proxy.rb', line 20

def app
  @app
end

#nested_proxiesObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



20
21
22
# File 'lib/pakyow/data/proxy.rb', line 20

def nested_proxies
  @nested_proxies
end

#proxied_callsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



20
21
22
# File 'lib/pakyow/data/proxy.rb', line 20

def proxied_calls
  @proxied_calls
end

#sourceObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



20
21
22
# File 'lib/pakyow/data/proxy.rb', line 20

def source
  @source
end

Class Method Details

._load(state) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/pakyow/data/proxy.rb', line 217

def self._load(state)
  state = Marshal.load(state)

  case state[:source]
  when Sources::Ephemeral
    ephemeral = state[:app].data.ephemeral(state[:source].source_name)
    ephemeral.instance_variable_set(:@source, state[:source])
    ephemeral
  else
    state[:app].data.public_send(state[:source]).apply(state[:proxied_calls])
  end
end

Instance Method Details

#_dump(_) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



207
208
209
210
211
212
213
214
215
# File 'lib/pakyow/data/proxy.rb', line 207

def _dump(_)
  Marshal.dump(
    {
      app: @app,
      source: @source.is_a?(Sources::Ephemeral) ? @source : @source.source_name,
      proxied_calls: @proxied_calls
    }
  )
end

#apply(proxied_calls) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



259
260
261
262
263
264
265
266
267
268
269
# File 'lib/pakyow/data/proxy.rb', line 259

def apply(proxied_calls)
  proxied_calls.inject(self) { |proxy, proxied_call|
    if proxied_call[2].any?
      proxy.public_send(proxied_call[0], *proxied_call[1]) do
        apply(proxied_call[2])
      end
    else
      proxy.public_send(proxied_call[0], *proxied_call[1])
    end
  }
end

#deep_dupObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



32
33
34
35
36
37
38
# File 'lib/pakyow/data/proxy.rb', line 32

def deep_dup
  super.tap do |duped|
    IVARS_TO_DUP.each do |ivar|
      duped.instance_variable_set(ivar, duped.instance_variable_get(ivar).deep_dup)
    end
  end
end

#qualificationsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/pakyow/data/proxy.rb', line 230

def qualifications
  @proxied_calls.inject(@source.qualifications) { |qualifications, proxied_call|
    qualifications_for_proxied_call = @source.class.qualifications(proxied_call[0]).dup

    # Populate argument qualifications with argument values.
    #
    qualifications_for_proxied_call.each do |qualification_key, qualification_value|
      if qualification_value.to_s.start_with?("__arg")
        arg_number = qualification_value.to_s.gsub(/[^0-9]/, "").to_i

        arg_value = proxied_call[1][arg_number]
        arg_value = case arg_value
        when Array
          arg_value.map { |each_value|
            @source.class.attributes[qualification_key][each_value]
          }
        else
          @source.class.attributes[qualification_key][arg_value]
        end

        qualifications_for_proxied_call[qualification_key] = arg_value
      end
    end

    qualifications.merge(qualifications_for_proxied_call)
  }
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


111
112
113
114
# File 'lib/pakyow/data/proxy.rb', line 111

def respond_to_missing?(method_name, include_private = false)
  return false if method_name == :marshal_dump || method_name == :marshal_load
  @source.command?(method_name) || @source.query?(method_name) || @source.modifier?(method_name) || @source.respond_to?(method_name, include_private)
end

#subscribable(boolean) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



197
198
199
200
201
# File 'lib/pakyow/data/proxy.rb', line 197

def subscribable(boolean)
  tap do
    @subscribable = boolean
  end
end

#subscribable?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


203
204
205
# File 'lib/pakyow/data/proxy.rb', line 203

def subscribable?
  @subscribable == true
end

#subscribe(subscriber, handler:, payload: nil, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/pakyow/data/proxy.rb', line 124

def subscribe(subscriber, handler:, payload: nil, &block)
  subscriptions = []

  if subscribable?
    subscription = {
      source: @source.source_name,
      ephemeral: @source.is_a?(Sources::Ephemeral),
      handler: handler,
      payload: payload,
      qualifications: qualifications,
      proxy: self
    }

    unless subscriptions.include?(subscription)
      subscriptions << subscription
    end

    @nested_proxies.each do |related_proxy|
      subscriptions.concat(
        related_proxy.subscribe_related(
          parent_source: @source,
          serialized_proxy: self,
          handler: handler,
          payload: payload
        )
      )
    end
  end

  @subscribers.register_subscriptions(subscriptions, subscriber: subscriber, &block)
end

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/pakyow/data/proxy.rb', line 156

def subscribe_related(parent_source:, serialized_proxy:, handler:, payload: nil)
  subscriptions = []

  if association = parent_source.class.find_association_to_source(@source)
    parent_source.each do |parent_result|
      subscription = {
        source: @source.source_name,
        handler: handler,
        payload: payload,
        qualifications: qualifications.merge(
          association.associated_query_field => parent_result[association.query_field]
        ),
        proxy: serialized_proxy
      }

      unless subscriptions.include?(subscription)
        subscriptions << subscription
      end
    end
  else
    Pakyow.logger.error "tried to subscribe a related source, but we don't know how it's related"
  end

  @nested_proxies.each do |related_proxy|
    subscriptions.concat(
      related_proxy.subscribe_related(
        parent_source: @source,
        serialized_proxy: serialized_proxy,
        handler: handler,
        payload: payload
      )
    )
  end

  subscriptions
end

#to_aryObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



116
117
118
# File 'lib/pakyow/data/proxy.rb', line 116

def to_ary
  to_a
end

#to_jsonObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



120
121
122
# File 'lib/pakyow/data/proxy.rb', line 120

def to_json(*)
  @source.to_json
end

#unsubscribeObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



193
194
195
# File 'lib/pakyow/data/proxy.rb', line 193

def unsubscribe
  subscribable(false)
end