pakyow-ui 0.11.3 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|