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,81 +0,0 @@
|
|
1
|
-
require_relative 'mutator'
|
2
|
-
require_relative 'channel_builder'
|
3
|
-
require_relative 'ui_view'
|
4
|
-
|
5
|
-
module Pakyow
|
6
|
-
module UI
|
7
|
-
# The UI context available during routing.
|
8
|
-
#
|
9
|
-
# @api public
|
10
|
-
class UI
|
11
|
-
attr_accessor :context
|
12
|
-
attr_reader :mutator
|
13
|
-
|
14
|
-
# Informs Pakyow that a mutation has occurred in application state,
|
15
|
-
# triggering all the necessary realtime view updates.
|
16
|
-
#
|
17
|
-
# @api public
|
18
|
-
def mutated(scope, data = nil, context = nil)
|
19
|
-
context ||= @context
|
20
|
-
|
21
|
-
MutationStore.instance.mutations(scope).each do |mutation|
|
22
|
-
view = UIView.new(mutation[:view_scope], mutation[:session])
|
23
|
-
|
24
|
-
qualified = true
|
25
|
-
|
26
|
-
# qualifiers are defined with the mutation
|
27
|
-
unless mutation[:qualifiers].empty? || data.nil?
|
28
|
-
mutation[:qualifiers].each_with_index do |qualifier, i|
|
29
|
-
qualified = false unless data[qualifier.to_sym].to_s == mutation[:query_args][i].to_s
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
qualified = false if data.nil? && !mutation[:qualifications].empty?
|
34
|
-
|
35
|
-
# qualifications are set on the subscription
|
36
|
-
unless !qualified || mutation[:qualifications].empty? || data.nil?
|
37
|
-
mutation[:qualifications].each_pair do |key, value|
|
38
|
-
qualified = false if data[key.to_sym].to_s != value.to_s
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
next unless qualified
|
43
|
-
|
44
|
-
mutable_data = Mutator.instance.mutable(scope, context).send(mutation[:query_name], *mutation[:query_args]).data
|
45
|
-
Mutator.instance.mutate(mutation[:mutation].to_sym, view, mutable_data)
|
46
|
-
|
47
|
-
channel = ChannelBuilder.build(
|
48
|
-
scope: mutation[:view_scope],
|
49
|
-
mutation: mutation[:mutation].to_sym,
|
50
|
-
qualifiers: mutation[:qualifiers],
|
51
|
-
data: mutable_data,
|
52
|
-
qualifications: mutation[:qualifications]
|
53
|
-
)
|
54
|
-
|
55
|
-
Pakyow.app.socket.push_message_to_socket_with_key(view.finalize, channel, mutation[:socket_key])
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# Addresses a component rendered on the client-side.
|
60
|
-
#
|
61
|
-
# @api public
|
62
|
-
def component(name, qualifications = {})
|
63
|
-
UIComponent.new(name, qualifications)
|
64
|
-
end
|
65
|
-
|
66
|
-
# @api private
|
67
|
-
def load(mutators, mutables)
|
68
|
-
# TODO: this is another pattern I see all over the place
|
69
|
-
@mutator = Mutator.instance.reset
|
70
|
-
|
71
|
-
mutators.each_pair do |scope, block|
|
72
|
-
@mutator.set(scope, &block)
|
73
|
-
end
|
74
|
-
|
75
|
-
mutables.each_pair do |scope, block|
|
76
|
-
@mutator.mutable(scope, &block)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require_relative 'ui_instructable'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
module UI
|
5
|
-
# Builds up instructions for changing view attributes.
|
6
|
-
#
|
7
|
-
# @api private
|
8
|
-
class UIAttrs
|
9
|
-
include Instructable
|
10
|
-
|
11
|
-
def nested_instruct_object(_method, _data, _scope)
|
12
|
-
UIAttrs.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def method_missing(method, value)
|
16
|
-
nested_instruct(method, value)
|
17
|
-
end
|
18
|
-
|
19
|
-
def class
|
20
|
-
method_missing(:class, nil)
|
21
|
-
end
|
22
|
-
|
23
|
-
def id
|
24
|
-
method_missing(:id, nil)
|
25
|
-
end
|
26
|
-
|
27
|
-
def <<(value)
|
28
|
-
method_missing(:insert, value)
|
29
|
-
end
|
30
|
-
|
31
|
-
def []=(method, value)
|
32
|
-
method_missing(method, value)
|
33
|
-
end
|
34
|
-
|
35
|
-
def [](method)
|
36
|
-
method_missing(method, nil)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require_relative 'ui_instructable'
|
2
|
-
|
3
|
-
module Pakyow
|
4
|
-
module UI
|
5
|
-
# An object for interacting with components rendered in a browser. Custom
|
6
|
-
# messages can be pushed and will be handled by the event listener defined
|
7
|
-
# on the client-side component.
|
8
|
-
#
|
9
|
-
# It's also possible to perform view transformations in realtime. Components
|
10
|
-
# implement a subset of transformations, including `scope` and `append`.
|
11
|
-
# This allows for finer control over particular components, completely
|
12
|
-
# bypassing mutables and mutators.
|
13
|
-
#
|
14
|
-
# @api public
|
15
|
-
class UIComponent
|
16
|
-
include Instructable
|
17
|
-
|
18
|
-
attr_reader :name, :view, :qualifications
|
19
|
-
|
20
|
-
# Intended to be created through the `ui.component` helper.
|
21
|
-
#
|
22
|
-
# @api private
|
23
|
-
def initialize(name, qualifications = {})
|
24
|
-
super()
|
25
|
-
@name = name
|
26
|
-
@qualifications = qualifications
|
27
|
-
end
|
28
|
-
|
29
|
-
# Pushes a message to the component.
|
30
|
-
#
|
31
|
-
# @api public
|
32
|
-
def push(payload = nil)
|
33
|
-
payload ||= { instruct: (root || self).finalize }
|
34
|
-
|
35
|
-
Pakyow.app.socket.push(
|
36
|
-
payload,
|
37
|
-
|
38
|
-
ChannelBuilder.build(
|
39
|
-
component: name,
|
40
|
-
qualifications: qualifications
|
41
|
-
)
|
42
|
-
)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Narrows the scope of component instructions.
|
46
|
-
#
|
47
|
-
# @api public
|
48
|
-
def scope(name)
|
49
|
-
nested_instruct(:scope, name.to_s, name)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Other supported transformation methods.
|
53
|
-
#
|
54
|
-
# @api public
|
55
|
-
%i(append prepend).each do |method|
|
56
|
-
define_method method do |value|
|
57
|
-
instruct(method, value)
|
58
|
-
push
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# @api private
|
63
|
-
def nested_instruct_object(_method, _data, _scope)
|
64
|
-
UIComponent.new(name, qualifications)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module UI
|
3
|
-
# A simple context object used for accessing the session.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
class UIContext
|
7
|
-
def initialize(session)
|
8
|
-
@session = session
|
9
|
-
end
|
10
|
-
|
11
|
-
def request
|
12
|
-
UIRequest.new(@session)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,117 +0,0 @@
|
|
1
|
-
module Pakyow
|
2
|
-
module UI
|
3
|
-
# Helper methods for instructable objects.
|
4
|
-
#
|
5
|
-
# @api private
|
6
|
-
module Instructable
|
7
|
-
def self.included(klass)
|
8
|
-
(@instructables ||= []) << klass
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.instructable?(object)
|
12
|
-
@instructables.select { |i|
|
13
|
-
object.is_a?(i)
|
14
|
-
}.any?
|
15
|
-
end
|
16
|
-
|
17
|
-
attr_reader :instructions
|
18
|
-
attr_accessor :root
|
19
|
-
|
20
|
-
def initialize
|
21
|
-
@instructions = []
|
22
|
-
end
|
23
|
-
|
24
|
-
def instruct(method, data)
|
25
|
-
@instructions << [clean_method(method), hashify(data)]
|
26
|
-
self
|
27
|
-
end
|
28
|
-
|
29
|
-
def nested_instruct(method, data, scope = nil)
|
30
|
-
view = nested_instruct_object(method, data, scope)
|
31
|
-
view.root = self
|
32
|
-
|
33
|
-
@instructions << [clean_method(method), hashify(data), view]
|
34
|
-
view
|
35
|
-
end
|
36
|
-
|
37
|
-
# Returns an instruction set for all view transformations.
|
38
|
-
#
|
39
|
-
# e.g. a value-less transformation:
|
40
|
-
# [[:remove, nil]]
|
41
|
-
#
|
42
|
-
# e.g. a transformation with a value:
|
43
|
-
# [[:text=, 'foo']]
|
44
|
-
#
|
45
|
-
# e.g. a nested transformation
|
46
|
-
# [[:scope, :post, [[:remove, nil]]]]
|
47
|
-
def finalize
|
48
|
-
@instructions.map { |instruction|
|
49
|
-
if Instructable.instructable?(instruction[2])
|
50
|
-
instruction[2] = instruction[2].finalize
|
51
|
-
end
|
52
|
-
|
53
|
-
instruction
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def mixin_bindings(data, bindings = {})
|
60
|
-
data.map { |bindable|
|
61
|
-
datum = bindable.to_hash.dup
|
62
|
-
Pakyow::Presenter::Binder.instance.bindings_for_scope(scoped_as, bindings).keys.each do |key|
|
63
|
-
result = Pakyow::Presenter::Binder.instance.value_for_scoped_prop(scoped_as, key, bindable, bindings, self)
|
64
|
-
|
65
|
-
if result.is_a?(Hash)
|
66
|
-
# we don't currently support view manipulations that occur in bindings
|
67
|
-
# TODO: look into what it would take to support this
|
68
|
-
result.delete(:view)
|
69
|
-
|
70
|
-
content = result.delete(:content)
|
71
|
-
if content.respond_to?(:to_proc)
|
72
|
-
content = content.to_proc.call()
|
73
|
-
end
|
74
|
-
|
75
|
-
datum[key] = {
|
76
|
-
__content: content,
|
77
|
-
__attrs: Hash[*result.flat_map { |k, v|
|
78
|
-
if v.respond_to?(:to_proc)
|
79
|
-
attrs = UIAttrs.new
|
80
|
-
v.call(attrs)
|
81
|
-
[k, attrs.finalize]
|
82
|
-
else
|
83
|
-
[k, v]
|
84
|
-
end
|
85
|
-
}]
|
86
|
-
}
|
87
|
-
else
|
88
|
-
datum[key] = result
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
datum
|
93
|
-
}
|
94
|
-
end
|
95
|
-
|
96
|
-
def hashify(data)
|
97
|
-
return hashify_datum(data) unless data.is_a?(Array)
|
98
|
-
|
99
|
-
data.map { |datum|
|
100
|
-
hashify_datum(datum)
|
101
|
-
}
|
102
|
-
end
|
103
|
-
|
104
|
-
def hashify_datum(datum)
|
105
|
-
if datum.respond_to?(:to_hash)
|
106
|
-
datum.to_hash
|
107
|
-
else
|
108
|
-
datum
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def clean_method(method)
|
113
|
-
method.to_s.delete('=').to_sym
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
@@ -1,200 +0,0 @@
|
|
1
|
-
require_relative 'ui_attrs'
|
2
|
-
require_relative 'ui_instructable'
|
3
|
-
require_relative 'ui_context'
|
4
|
-
require_relative 'ui_request'
|
5
|
-
|
6
|
-
module Pakyow
|
7
|
-
module UI
|
8
|
-
# Translates view transformations to instructions.
|
9
|
-
#
|
10
|
-
# @api private
|
11
|
-
class UIView
|
12
|
-
include Instructable
|
13
|
-
include Pakyow::Helpers
|
14
|
-
|
15
|
-
def initialize(scope, session = {})
|
16
|
-
super()
|
17
|
-
@scope = scope.to_sym
|
18
|
-
@session = session
|
19
|
-
@context = UIContext.new(session)
|
20
|
-
end
|
21
|
-
|
22
|
-
def nested_instruct_object(_method, _data, scope)
|
23
|
-
UIView.new(scope || @scope, @session)
|
24
|
-
end
|
25
|
-
|
26
|
-
def scoped_as
|
27
|
-
@scope
|
28
|
-
end
|
29
|
-
|
30
|
-
def attrs_instruct
|
31
|
-
attrs = UIAttrs.new
|
32
|
-
@instructions << [:attrs, nil, attrs]
|
33
|
-
attrs
|
34
|
-
end
|
35
|
-
|
36
|
-
### view methods w/o args
|
37
|
-
|
38
|
-
%i(
|
39
|
-
remove
|
40
|
-
clear
|
41
|
-
).each do |method|
|
42
|
-
define_method method do
|
43
|
-
instruct(method, nil)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
### view methods w/ args
|
48
|
-
|
49
|
-
%i(
|
50
|
-
title=
|
51
|
-
text=
|
52
|
-
html=
|
53
|
-
append
|
54
|
-
prepend
|
55
|
-
after
|
56
|
-
before
|
57
|
-
replace
|
58
|
-
use
|
59
|
-
).each do |method|
|
60
|
-
define_method method do |value|
|
61
|
-
instruct(method, value.to_s)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
### misc view methods
|
66
|
-
|
67
|
-
def with(&block)
|
68
|
-
if block.arity == 0
|
69
|
-
instance_exec(&block)
|
70
|
-
else
|
71
|
-
yield(self)
|
72
|
-
end
|
73
|
-
|
74
|
-
self
|
75
|
-
end
|
76
|
-
|
77
|
-
def match(data)
|
78
|
-
instruct(:match, Array.ensure(data))
|
79
|
-
end
|
80
|
-
|
81
|
-
def scope(name)
|
82
|
-
nested_instruct(:scope, name.to_s, name)
|
83
|
-
end
|
84
|
-
|
85
|
-
def attrs
|
86
|
-
attrs_instruct
|
87
|
-
end
|
88
|
-
|
89
|
-
### view methods that change context
|
90
|
-
|
91
|
-
%i(
|
92
|
-
prop
|
93
|
-
component
|
94
|
-
).each do |method|
|
95
|
-
define_method method do |value|
|
96
|
-
nested_instruct(method, value.to_s)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
### view methods that continue into a new context
|
101
|
-
|
102
|
-
def version(data, &block)
|
103
|
-
nested = nested_instruct(:version, data)
|
104
|
-
Array.ensure(data).each do |datum|
|
105
|
-
sub = UIView.new(@scope)
|
106
|
-
|
107
|
-
if block.arity == 1
|
108
|
-
sub.instance_exec(datum, &block)
|
109
|
-
else
|
110
|
-
block.call(sub, datum)
|
111
|
-
end
|
112
|
-
|
113
|
-
nested.instructions << sub.finalize
|
114
|
-
end
|
115
|
-
|
116
|
-
self
|
117
|
-
end
|
118
|
-
|
119
|
-
def for(data, &block)
|
120
|
-
nested = nested_instruct(:for, data)
|
121
|
-
Array.ensure(data).each do |datum|
|
122
|
-
sub = UIView.new(@scope)
|
123
|
-
|
124
|
-
if block.arity == 1
|
125
|
-
sub.instance_exec(datum, &block)
|
126
|
-
else
|
127
|
-
block.call(sub, datum)
|
128
|
-
end
|
129
|
-
|
130
|
-
nested.instructions << sub.finalize
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def for_with_index(*args, &block)
|
135
|
-
self.for(*args, &block)
|
136
|
-
end
|
137
|
-
|
138
|
-
def repeat(data, &block)
|
139
|
-
nested = nested_instruct(:repeat, data)
|
140
|
-
Array.ensure(data).each do |datum|
|
141
|
-
sub = UIView.new(@scope)
|
142
|
-
|
143
|
-
if block.arity == 1
|
144
|
-
sub.instance_exec(datum, &block)
|
145
|
-
else
|
146
|
-
block.call(sub, datum)
|
147
|
-
end
|
148
|
-
|
149
|
-
nested.instructions << sub.finalize
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def repeat_with_index(*args, &block)
|
154
|
-
repeat(*args, &block)
|
155
|
-
end
|
156
|
-
|
157
|
-
def bind(data, bindings: {}, context: nil, &block)
|
158
|
-
# TODO: handle context?
|
159
|
-
|
160
|
-
nested = nested_instruct(:bind, mixin_bindings(Array.ensure(data), bindings))
|
161
|
-
return self unless block_given?
|
162
|
-
|
163
|
-
data.each do |datum|
|
164
|
-
sub = UIView.new(@scope)
|
165
|
-
|
166
|
-
if block.arity == 1
|
167
|
-
sub.instance_exec(datum, &block)
|
168
|
-
else
|
169
|
-
block.call(sub, datum)
|
170
|
-
end
|
171
|
-
|
172
|
-
nested.instructions << sub.finalize
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def bind_with_index(*args, &block)
|
177
|
-
bind(*args, &block)
|
178
|
-
end
|
179
|
-
|
180
|
-
def apply(data, bindings: {}, context: nil, &block)
|
181
|
-
# TODO: handle context?
|
182
|
-
|
183
|
-
nested = nested_instruct(:apply, mixin_bindings(Array.ensure(data), bindings))
|
184
|
-
return self unless block_given?
|
185
|
-
|
186
|
-
data.each do |datum|
|
187
|
-
sub = UIView.new(@scope, @session)
|
188
|
-
|
189
|
-
if block.arity == 1
|
190
|
-
sub.instance_exec(datum, &block)
|
191
|
-
else
|
192
|
-
block.call(sub, datum)
|
193
|
-
end
|
194
|
-
|
195
|
-
nested.instructions << sub.finalize
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
data/pakyow-ui/lib/pakyow/ui.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'pakyow/ui/base'
|
data/pakyow-ui/lib/pakyow-ui.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'pakyow/ui'
|