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.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/{pakyow-ui/CHANGELOG.md → CHANGELOG.md} +0 -0
  3. data/LICENSE +4 -0
  4. data/{pakyow-ui/README.md → README.md} +1 -2
  5. data/lib/pakyow/ui/behavior/recording.rb +51 -0
  6. data/lib/pakyow/ui/behavior/rendering/install_transforms.rb +47 -0
  7. data/lib/pakyow/ui/behavior/rendering.rb +105 -0
  8. data/lib/pakyow/ui/behavior/timeouts.rb +31 -0
  9. data/lib/pakyow/ui/framework.rb +75 -0
  10. data/lib/pakyow/ui/handler.rb +42 -0
  11. data/lib/pakyow/ui/helpers.rb +19 -0
  12. data/lib/pakyow/ui/recordable/attribute.rb +39 -0
  13. data/lib/pakyow/ui/recordable/attributes.rb +50 -0
  14. data/lib/pakyow/ui/recordable/helpers/client_remapping.rb +30 -0
  15. data/lib/pakyow/ui/recordable.rb +303 -0
  16. data/lib/pakyow/ui.rb +9 -0
  17. metadata +46 -60
  18. data/pakyow-ui/LICENSE +0 -20
  19. data/pakyow-ui/lib/pakyow/ui/base.rb +0 -26
  20. data/pakyow-ui/lib/pakyow/ui/channel_builder.rb +0 -55
  21. data/pakyow-ui/lib/pakyow/ui/config.rb +0 -11
  22. data/pakyow-ui/lib/pakyow/ui/ext/app.rb +0 -52
  23. data/pakyow-ui/lib/pakyow/ui/ext/view_context.rb +0 -30
  24. data/pakyow-ui/lib/pakyow/ui/fetch_view_handler.rb +0 -68
  25. data/pakyow-ui/lib/pakyow/ui/helpers.rb +0 -15
  26. data/pakyow-ui/lib/pakyow/ui/mock_mutation_eval.rb +0 -25
  27. data/pakyow-ui/lib/pakyow/ui/mutable.rb +0 -99
  28. data/pakyow-ui/lib/pakyow/ui/mutable_data.rb +0 -21
  29. data/pakyow-ui/lib/pakyow/ui/mutate_context.rb +0 -64
  30. data/pakyow-ui/lib/pakyow/ui/mutation_set.rb +0 -38
  31. data/pakyow-ui/lib/pakyow/ui/mutation_store.rb +0 -41
  32. data/pakyow-ui/lib/pakyow/ui/mutator.rb +0 -63
  33. data/pakyow-ui/lib/pakyow/ui/no_op_view.rb +0 -87
  34. data/pakyow-ui/lib/pakyow/ui/registries/redis_mutation_registry.rb +0 -70
  35. data/pakyow-ui/lib/pakyow/ui/registries/simple_mutation_registry.rb +0 -37
  36. data/pakyow-ui/lib/pakyow/ui/ui.rb +0 -81
  37. data/pakyow-ui/lib/pakyow/ui/ui_attrs.rb +0 -40
  38. data/pakyow-ui/lib/pakyow/ui/ui_component.rb +0 -68
  39. data/pakyow-ui/lib/pakyow/ui/ui_context.rb +0 -16
  40. data/pakyow-ui/lib/pakyow/ui/ui_instructable.rb +0 -117
  41. data/pakyow-ui/lib/pakyow/ui/ui_request.rb +0 -14
  42. data/pakyow-ui/lib/pakyow/ui/ui_view.rb +0 -200
  43. data/pakyow-ui/lib/pakyow/ui.rb +0 -1
  44. 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,14 +0,0 @@
1
- module Pakyow
2
- module UI
3
- # A simple request object used for accessing the session.
4
- #
5
- # @api private
6
- class UIRequest
7
- attr_reader :session
8
-
9
- def initialize(session)
10
- @session = Hash.strhash(session)
11
- end
12
- end
13
- end
14
- 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
@@ -1 +0,0 @@
1
- require 'pakyow/ui/base'
@@ -1 +0,0 @@
1
- require 'pakyow/ui'