pakyow-ui 0.11.3 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/{pakyow-ui/CHANGELOG.md → CHANGELOG.md} +0 -0
- data/LICENSE +4 -0
- data/{pakyow-ui/README.md → README.md} +1 -2
- data/lib/pakyow/ui/behavior/recording.rb +51 -0
- data/lib/pakyow/ui/behavior/rendering/install_transforms.rb +47 -0
- data/lib/pakyow/ui/behavior/rendering.rb +105 -0
- data/lib/pakyow/ui/behavior/timeouts.rb +31 -0
- data/lib/pakyow/ui/framework.rb +75 -0
- data/lib/pakyow/ui/handler.rb +42 -0
- data/lib/pakyow/ui/helpers.rb +19 -0
- data/lib/pakyow/ui/recordable/attribute.rb +39 -0
- data/lib/pakyow/ui/recordable/attributes.rb +50 -0
- data/lib/pakyow/ui/recordable/helpers/client_remapping.rb +30 -0
- data/lib/pakyow/ui/recordable.rb +303 -0
- data/lib/pakyow/ui.rb +9 -0
- metadata +46 -60
- data/pakyow-ui/LICENSE +0 -20
- data/pakyow-ui/lib/pakyow/ui/base.rb +0 -26
- data/pakyow-ui/lib/pakyow/ui/channel_builder.rb +0 -55
- data/pakyow-ui/lib/pakyow/ui/config.rb +0 -11
- data/pakyow-ui/lib/pakyow/ui/ext/app.rb +0 -52
- data/pakyow-ui/lib/pakyow/ui/ext/view_context.rb +0 -30
- data/pakyow-ui/lib/pakyow/ui/fetch_view_handler.rb +0 -68
- data/pakyow-ui/lib/pakyow/ui/helpers.rb +0 -15
- data/pakyow-ui/lib/pakyow/ui/mock_mutation_eval.rb +0 -25
- data/pakyow-ui/lib/pakyow/ui/mutable.rb +0 -99
- data/pakyow-ui/lib/pakyow/ui/mutable_data.rb +0 -21
- data/pakyow-ui/lib/pakyow/ui/mutate_context.rb +0 -64
- data/pakyow-ui/lib/pakyow/ui/mutation_set.rb +0 -38
- data/pakyow-ui/lib/pakyow/ui/mutation_store.rb +0 -41
- data/pakyow-ui/lib/pakyow/ui/mutator.rb +0 -63
- data/pakyow-ui/lib/pakyow/ui/no_op_view.rb +0 -87
- data/pakyow-ui/lib/pakyow/ui/registries/redis_mutation_registry.rb +0 -70
- data/pakyow-ui/lib/pakyow/ui/registries/simple_mutation_registry.rb +0 -37
- data/pakyow-ui/lib/pakyow/ui/ui.rb +0 -81
- data/pakyow-ui/lib/pakyow/ui/ui_attrs.rb +0 -40
- data/pakyow-ui/lib/pakyow/ui/ui_component.rb +0 -68
- data/pakyow-ui/lib/pakyow/ui/ui_context.rb +0 -16
- data/pakyow-ui/lib/pakyow/ui/ui_instructable.rb +0 -117
- data/pakyow-ui/lib/pakyow/ui/ui_request.rb +0 -14
- data/pakyow-ui/lib/pakyow/ui/ui_view.rb +0 -200
- data/pakyow-ui/lib/pakyow/ui.rb +0 -1
- data/pakyow-ui/lib/pakyow-ui.rb +0 -1
@@ -1,30 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module Presenter
|
3
|
-
class ViewContext
|
4
|
-
MSG_NONCOMPONENT = 'Cannot subscribe a non-component view'
|
5
|
-
|
6
|
-
# Mutates a view with a registered mutator.
|
7
|
-
#
|
8
|
-
# @api public
|
9
|
-
def mutate(mutator, data: nil, with: nil)
|
10
|
-
Pakyow::UI::Mutator.instance.mutate(mutator, self, data || with || [])
|
11
|
-
end
|
12
|
-
|
13
|
-
# Subscribes a view and sets the `data-channel` attribute.
|
14
|
-
#
|
15
|
-
# @api public
|
16
|
-
def subscribe(qualifications = {})
|
17
|
-
fail ArgumentError, MSG_NONCOMPONENT unless component?
|
18
|
-
|
19
|
-
channel = Pakyow::UI::ChannelBuilder.build(
|
20
|
-
component: component_name,
|
21
|
-
qualifications: qualifications
|
22
|
-
)
|
23
|
-
|
24
|
-
context.socket.subscribe(channel)
|
25
|
-
attrs.send(:'data-channel=', channel)
|
26
|
-
self
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require_relative 'no_op_view'
|
2
|
-
|
3
|
-
# Makes it possible to fetch a particular part of a view for a path. Calls a
|
4
|
-
# route with all view actions becoming no-ops. Then a query is run against the
|
5
|
-
# final view, pulling out the part that was requested.
|
6
|
-
#
|
7
|
-
# Expects the following in the message:
|
8
|
-
#
|
9
|
-
# - uri: the route to call
|
10
|
-
# - lookup: the view query
|
11
|
-
#
|
12
|
-
# Lookup currently supports the following keys:
|
13
|
-
#
|
14
|
-
# - channel
|
15
|
-
# - version
|
16
|
-
# - container
|
17
|
-
# - partial
|
18
|
-
# - scope
|
19
|
-
# - prop
|
20
|
-
#
|
21
|
-
Pakyow::Realtime.handler :'fetch-view' do |message, session, response|
|
22
|
-
env = Rack::MockRequest.env_for(message['uri'])
|
23
|
-
env['pakyow.socket'] = true
|
24
|
-
env['rack.session'] = session
|
25
|
-
|
26
|
-
context = Pakyow::CallContext.new(env)
|
27
|
-
|
28
|
-
def context.view
|
29
|
-
Pakyow::Presenter::NoOpView.new(
|
30
|
-
Pakyow::Presenter::ViewContext.new(@presenter.view, self),
|
31
|
-
self
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
app_response = context.process.finish
|
36
|
-
|
37
|
-
body = ''
|
38
|
-
lookup = message['lookup']
|
39
|
-
view = context.presenter.view
|
40
|
-
|
41
|
-
channel = lookup['channel']
|
42
|
-
|
43
|
-
if channel
|
44
|
-
unqualified_channel = channel.split('::')[0]
|
45
|
-
view_for_channel = view.composed.doc.channel(unqualified_channel)
|
46
|
-
|
47
|
-
if view_for_channel
|
48
|
-
view_for_channel.set_attribute(:'data-channel', channel)
|
49
|
-
body = view_for_channel.to_html
|
50
|
-
end
|
51
|
-
else
|
52
|
-
lookup.each_pair do |key, value|
|
53
|
-
next if key == 'version'
|
54
|
-
view = view.send(key.to_sym, value.to_sym)
|
55
|
-
end
|
56
|
-
|
57
|
-
if view.is_a?(Pakyow::Presenter::ViewVersion)
|
58
|
-
body = view.use((lookup['version'] || :default).to_sym).to_html
|
59
|
-
else
|
60
|
-
body = view.to_html
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
response[:status] = app_response[0]
|
65
|
-
response[:headers] = app_response[1]
|
66
|
-
response[:body] = body
|
67
|
-
response
|
68
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module Presenter
|
3
|
-
# Used by NoOpView to perform mutations in a no-op manner.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
class MockMutationEval
|
7
|
-
def initialize(mutation_name, relation_name, view)
|
8
|
-
@mutation_name = mutation_name
|
9
|
-
@relation_name = relation_name
|
10
|
-
@view = view
|
11
|
-
end
|
12
|
-
|
13
|
-
# NOTE we don't care about qualifiers here since we're just getting
|
14
|
-
# the proper view template; not actually setting it up with data
|
15
|
-
def subscribe(*_args)
|
16
|
-
channel = Pakyow::UI::ChannelBuilder.build(
|
17
|
-
scope: @view.scoped_as,
|
18
|
-
mutation: @mutation_name
|
19
|
-
)
|
20
|
-
|
21
|
-
@view.attrs.send(:'data-channel=', channel)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
require_relative 'mutable_data'
|
2
|
-
|
3
|
-
# TODO: make it possible to register this as data instead of mutables
|
4
|
-
|
5
|
-
module Pakyow
|
6
|
-
module UI
|
7
|
-
# Mutables enable PakyowUI to automatically handle changes in application
|
8
|
-
# state by interacting with the data layer in a declarative manner.
|
9
|
-
#
|
10
|
-
# Wraps a data source (such as a model object) and provides a convenient
|
11
|
-
# interface for defining and executing queries and actions. Queries accept
|
12
|
-
# parameters and return data sets. Actions cause a state change in
|
13
|
-
# application state.
|
14
|
-
#
|
15
|
-
# Once defined, all interactions with the data layer should occur through
|
16
|
-
# Mutables via the `data` helper method. When an action is performed that
|
17
|
-
# changes the state of the application, Pakyow will propogate the change
|
18
|
-
# through to all other connected clients automatically.
|
19
|
-
#
|
20
|
-
# Mutables should be registered with the `Pakyow::App.mutable` helper. The
|
21
|
-
# defined block will be executed in context of a `Mutable` instance.
|
22
|
-
#
|
23
|
-
# @api public
|
24
|
-
class Mutable
|
25
|
-
include Helpers
|
26
|
-
|
27
|
-
attr_reader :context
|
28
|
-
|
29
|
-
# @api private
|
30
|
-
def initialize(context, scope, &block)
|
31
|
-
@context = context
|
32
|
-
@scope = scope
|
33
|
-
@actions = {}
|
34
|
-
@queries = {}
|
35
|
-
|
36
|
-
instance_exec(&block)
|
37
|
-
end
|
38
|
-
|
39
|
-
# Sets the model object.
|
40
|
-
#
|
41
|
-
# @api public
|
42
|
-
def model(model_class, type: nil)
|
43
|
-
@model_class = model_class
|
44
|
-
|
45
|
-
return if type.nil?
|
46
|
-
@model_type = type
|
47
|
-
|
48
|
-
# TODO: load default actions / queries based on type
|
49
|
-
end
|
50
|
-
|
51
|
-
# Defines an action.
|
52
|
-
#
|
53
|
-
# @api public
|
54
|
-
def action(name, mutation: true, &block)
|
55
|
-
@actions[name] = {
|
56
|
-
block: block,
|
57
|
-
mutation: mutation
|
58
|
-
}
|
59
|
-
end
|
60
|
-
|
61
|
-
# Defines a query.
|
62
|
-
#
|
63
|
-
# @api public
|
64
|
-
def query(name, &block)
|
65
|
-
@queries[name] = block
|
66
|
-
end
|
67
|
-
|
68
|
-
# Handles calling queries or actions. Enables convenience like:
|
69
|
-
#
|
70
|
-
# data(:some_data).{action or query}
|
71
|
-
#
|
72
|
-
# @api public
|
73
|
-
def method_missing(method, *args)
|
74
|
-
action = @actions[method]
|
75
|
-
query = @queries[method]
|
76
|
-
|
77
|
-
if action
|
78
|
-
call_action(action, *args)
|
79
|
-
elsif query
|
80
|
-
call_query(query, method, *args)
|
81
|
-
else
|
82
|
-
fail ArgumentError, "Could not find query or action named #{method}"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def call_action(action, *args)
|
89
|
-
result = action[:block].call(*args)
|
90
|
-
@context.ui.mutated(@scope, result, @context) if action[:mutation]
|
91
|
-
result
|
92
|
-
end
|
93
|
-
|
94
|
-
def call_query(query, method, *args)
|
95
|
-
MutableData.new(query, method, args, @scope)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module UI
|
3
|
-
# Adds metadata to a dataset returned by a Mutable query.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
class MutableData
|
7
|
-
attr_reader :query_name, :query_args, :scope
|
8
|
-
|
9
|
-
def initialize(query, query_name, query_args, scope)
|
10
|
-
@query = query
|
11
|
-
@query_name = query_name
|
12
|
-
@query_args = query_args
|
13
|
-
@scope = scope
|
14
|
-
end
|
15
|
-
|
16
|
-
def data
|
17
|
-
@data ||= @query.call(*@query_args)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
require_relative 'channel_builder'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
module UI
|
5
|
-
# Provides helper methods to perform in context of a mutation. For example:
|
6
|
-
#
|
7
|
-
# view.scope(:foo).mutate(:bar).subscribe
|
8
|
-
#
|
9
|
-
# In the above example `mutate` returns a MutateContext object on which
|
10
|
-
# `subscribe` is called.
|
11
|
-
#
|
12
|
-
# @api public
|
13
|
-
class MutateContext
|
14
|
-
attr_reader :mutation, :view, :data
|
15
|
-
|
16
|
-
# Creates a new context. Intended to be created by a Mutator.
|
17
|
-
#
|
18
|
-
# @api private
|
19
|
-
def initialize(mutation, view, data)
|
20
|
-
@mutation = mutation
|
21
|
-
@view = view
|
22
|
-
@data = data
|
23
|
-
end
|
24
|
-
|
25
|
-
# Subscribes a mutation with optional qualifications. Qualifications are
|
26
|
-
# used to control the scope of future mutations. For example:
|
27
|
-
#
|
28
|
-
# view.scope(:foo).mutate(:bar).subscribe(user_id: 1)
|
29
|
-
#
|
30
|
-
# In the above example, a subscription is created qualified by `user_id`.
|
31
|
-
# Only mutations occuring with the same qualifications will cause the
|
32
|
-
# mutation to be performed again, triggering a view refresh.
|
33
|
-
#
|
34
|
-
# ui.mutated(:foo, user_id: 1)
|
35
|
-
#
|
36
|
-
# @api public
|
37
|
-
def subscribe(qualifications = {})
|
38
|
-
if data.is_a?(MutableData) && !view.context.request.env['pakyow.socket']
|
39
|
-
MutationStore.instance.register(self, view, data, qualifications, view.context.request.session)
|
40
|
-
end
|
41
|
-
|
42
|
-
channel = ChannelBuilder.build(
|
43
|
-
scope: view.scoped_as,
|
44
|
-
mutation: mutation[:name],
|
45
|
-
qualifiers: mutation[:qualifiers],
|
46
|
-
data: data,
|
47
|
-
qualifications: qualifications
|
48
|
-
)
|
49
|
-
|
50
|
-
# subscribe to the channel
|
51
|
-
view.context.socket.subscribe(channel)
|
52
|
-
|
53
|
-
# handle setting the channel on the view
|
54
|
-
if view.is_a?(Presenter::ViewContext)
|
55
|
-
working_view = view.instance_variable_get(:@view)
|
56
|
-
else
|
57
|
-
working_view = view
|
58
|
-
end
|
59
|
-
|
60
|
-
working_view.attrs.send(:'data-channel=', channel)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module UI
|
3
|
-
# Stores mutations.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
class MutationSet
|
7
|
-
attr_reader :mutations
|
8
|
-
|
9
|
-
def initialize(&block)
|
10
|
-
@mutations = {}
|
11
|
-
instance_exec(&block)
|
12
|
-
end
|
13
|
-
|
14
|
-
# NOTE I do have some concerns about defining qualifiers in this way;
|
15
|
-
# mainly because it will lead to having lots of versions of the same
|
16
|
-
# mutator just so the proper channels will be created.
|
17
|
-
#
|
18
|
-
# It's could end up being better to pass qualifiers to `subscribe`;
|
19
|
-
# however it feels premature to make this decision since it'll lead
|
20
|
-
# to a large increase in complexity to add at this point.
|
21
|
-
def mutator(name, qualify: [], &block)
|
22
|
-
@mutations[name] = {
|
23
|
-
fn: block,
|
24
|
-
qualifiers: Array.ensure(qualify),
|
25
|
-
name: name
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
def mutation(name)
|
30
|
-
@mutations.fetch(name)
|
31
|
-
end
|
32
|
-
|
33
|
-
def each(&block)
|
34
|
-
@mutations.each(&block)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module UI
|
3
|
-
# Stores mutations that have occurred in the configured registry.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
class MutationStore
|
7
|
-
include Singleton
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@registry = Config.ui.registry.instance
|
11
|
-
end
|
12
|
-
|
13
|
-
def register(mutate_context, view, mutable_data, qualifications, session)
|
14
|
-
@registry.register(
|
15
|
-
mutable_data.scope,
|
16
|
-
|
17
|
-
view_scope: view.scoped_as,
|
18
|
-
mutation: mutate_context.mutation[:name],
|
19
|
-
qualifiers: mutate_context.mutation[:qualifiers],
|
20
|
-
qualifications: qualifications,
|
21
|
-
query_name: mutable_data.query_name,
|
22
|
-
query_args: mutable_data.query_args,
|
23
|
-
session: session.to_hash,
|
24
|
-
socket_key: mutate_context.view.context.socket_digest(mutate_context.view.context.socket_connection_id)
|
25
|
-
)
|
26
|
-
end
|
27
|
-
|
28
|
-
def unregister(socket_key)
|
29
|
-
@registry.unregister(socket_key)
|
30
|
-
end
|
31
|
-
|
32
|
-
def mutations(scope)
|
33
|
-
@registry.mutations(scope) || []
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
Pakyow::Realtime::Websocket.on :leave do
|
40
|
-
Pakyow::UI::MutationStore.instance.unregister(socket_digest(socket_connection_id))
|
41
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require_relative 'mutation_set'
|
2
|
-
require_relative 'mutate_context'
|
3
|
-
|
4
|
-
module Pakyow
|
5
|
-
module UI
|
6
|
-
# Performs mutations on views.
|
7
|
-
#
|
8
|
-
# @api private
|
9
|
-
class Mutator
|
10
|
-
include Singleton
|
11
|
-
|
12
|
-
attr_reader :sets
|
13
|
-
|
14
|
-
# @api private
|
15
|
-
def initialize
|
16
|
-
reset
|
17
|
-
end
|
18
|
-
|
19
|
-
def reset
|
20
|
-
@sets = {}
|
21
|
-
@mutables = {}
|
22
|
-
self
|
23
|
-
end
|
24
|
-
|
25
|
-
def set(scope, &block)
|
26
|
-
@sets[scope] = MutationSet.new(&block)
|
27
|
-
end
|
28
|
-
|
29
|
-
def mutable(scope, context = nil, &block)
|
30
|
-
if block_given?
|
31
|
-
@mutables[scope] = block
|
32
|
-
else
|
33
|
-
# TODO: inefficient to have to execute the block each time
|
34
|
-
Mutable.new(context, scope, &@mutables[scope])
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def mutation(scope, name)
|
39
|
-
if mutations = mutations_by_scope(scope)
|
40
|
-
mutations.mutation(name)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# TODO: rename to mutation_set_for_scope
|
45
|
-
def mutations_by_scope(scope)
|
46
|
-
@sets[scope]
|
47
|
-
end
|
48
|
-
|
49
|
-
def mutate(mutation_name, view, data)
|
50
|
-
if mutation = mutation(view.scoped_as, mutation_name)
|
51
|
-
if data.is_a?(MutableData)
|
52
|
-
working_data = data.data
|
53
|
-
else
|
54
|
-
working_data = data
|
55
|
-
end
|
56
|
-
|
57
|
-
view.instance_exec(view, working_data, &mutation[:fn])
|
58
|
-
MutateContext.new(mutation, view, data)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
require_relative 'mock_mutation_eval'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
module Presenter
|
5
|
-
# Stands in for a real View object and makes any attempted transformation
|
6
|
-
# a no-op.
|
7
|
-
#
|
8
|
-
# @api private
|
9
|
-
class NoOpView
|
10
|
-
include Helpers
|
11
|
-
VIEW_CLASSES = [ViewContext]
|
12
|
-
|
13
|
-
# The arities of misc view methods that switch the behavior from
|
14
|
-
# instance_exec to yield.
|
15
|
-
#
|
16
|
-
EXEC_ARITIES = { with: 0, for: 1, for_with_index: 2, repeat: 1,
|
17
|
-
repeat_with_index: 2, bind: 1, bind_with_index: 2,
|
18
|
-
apply: 1 }
|
19
|
-
|
20
|
-
def initialize(view, context)
|
21
|
-
@view = view
|
22
|
-
@context = context
|
23
|
-
end
|
24
|
-
|
25
|
-
def is_a?(klass)
|
26
|
-
@view.is_a?(klass)
|
27
|
-
end
|
28
|
-
|
29
|
-
# View methods that should be a no-op
|
30
|
-
#
|
31
|
-
%i(bind bind_with_index apply).each do |method|
|
32
|
-
define_method(method) do |_data, **_kargs, &_block|
|
33
|
-
self
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def mutate(mutator, with: nil, data: nil)
|
38
|
-
MockMutationEval.new(mutator, with || data, self)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Pass these through, handling the return value.
|
42
|
-
#
|
43
|
-
def method_missing(method, *args, &block)
|
44
|
-
ret = @view.send(method, *args, &wrap(method, &block))
|
45
|
-
handle_return_value(ret)
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def view?(obj)
|
51
|
-
VIEW_CLASSES.include?(obj.class)
|
52
|
-
end
|
53
|
-
|
54
|
-
# Returns a new context for returned views, or the return value.
|
55
|
-
#
|
56
|
-
def handle_return_value(value)
|
57
|
-
return NoOpView.new(value, @context) if view?(value)
|
58
|
-
|
59
|
-
value
|
60
|
-
end
|
61
|
-
|
62
|
-
# Wrap the block, substituting the view with the current view context.
|
63
|
-
#
|
64
|
-
def wrap(method, &block)
|
65
|
-
return if block.nil?
|
66
|
-
|
67
|
-
proc do |*args|
|
68
|
-
ctx = args.map! { |arg|
|
69
|
-
view?(arg) ? NoOpView.new(arg, @context) : arg
|
70
|
-
}.find { |arg| arg.is_a?(ViewContext) }
|
71
|
-
|
72
|
-
case block.arity
|
73
|
-
when EXEC_ARITIES[method]
|
74
|
-
# Rejecting ViewContext handles the edge cases around the order of
|
75
|
-
# arguments from view methods (since view is not present in some
|
76
|
-
# situations and when it is present, is always the first arg).
|
77
|
-
ctx.instance_exec(*args.reject { |arg|
|
78
|
-
arg.is_a?(ViewContext)
|
79
|
-
}, &block)
|
80
|
-
else
|
81
|
-
block.call(*args)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
module UI
|
5
|
-
# Manages mutations.
|
6
|
-
#
|
7
|
-
# This is the default registry in production systems and is required in
|
8
|
-
# deployments with more than one app instance.
|
9
|
-
#
|
10
|
-
# @api private
|
11
|
-
class RedisMutationRegistry
|
12
|
-
include Singleton
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
end
|
16
|
-
|
17
|
-
def register(scope, mutation)
|
18
|
-
Pakyow::Realtime.redis.sadd(key(scope: scope, socket_key: mutation[:socket_key]), mutation.to_json)
|
19
|
-
end
|
20
|
-
|
21
|
-
def mutations(scope)
|
22
|
-
mutations = []
|
23
|
-
|
24
|
-
keys(key(scope: scope)) do |key|
|
25
|
-
Pakyow::Realtime.redis.smembers(key).each do |m|
|
26
|
-
mutations << Hash.strhash(JSON.parse(m))
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
mutations
|
31
|
-
end
|
32
|
-
|
33
|
-
def unregister(socket_key)
|
34
|
-
keys(key(socket_key: socket_key)) do |key|
|
35
|
-
Pakyow::Realtime.redis.del(key)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def key(scope: nil, socket_key: nil)
|
42
|
-
if socket_key.nil?
|
43
|
-
base = "*:"
|
44
|
-
else
|
45
|
-
base = "#{socket_key}:"
|
46
|
-
end
|
47
|
-
|
48
|
-
if scope.nil?
|
49
|
-
"#{base}*"
|
50
|
-
else
|
51
|
-
"#{base}pui-mutation-#{scope}"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def keys(match)
|
56
|
-
cursor = 0
|
57
|
-
|
58
|
-
loop do
|
59
|
-
cursor, keys = Pakyow::Realtime.redis.scan(cursor, match: match)
|
60
|
-
|
61
|
-
keys.each do |key|
|
62
|
-
yield key
|
63
|
-
end
|
64
|
-
|
65
|
-
break if cursor == '0'
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module UI
|
3
|
-
# Manages mutations.
|
4
|
-
#
|
5
|
-
# Intended only for use in development or single app-instance deployments.
|
6
|
-
#
|
7
|
-
# @api private
|
8
|
-
class SimpleMutationRegistry
|
9
|
-
include Singleton
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
reset
|
13
|
-
end
|
14
|
-
|
15
|
-
def reset
|
16
|
-
@mutations = {}
|
17
|
-
end
|
18
|
-
|
19
|
-
def register(scope, mutation)
|
20
|
-
@mutations[scope] ||= []
|
21
|
-
@mutations[scope] << mutation
|
22
|
-
end
|
23
|
-
|
24
|
-
def unregister(socket_key)
|
25
|
-
@mutations.each do |_, mutations|
|
26
|
-
mutations.delete_if { |mutation|
|
27
|
-
mutation[:socket_key] == socket_key
|
28
|
-
}
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def mutations(scope)
|
33
|
-
@mutations[scope]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|