motion 0.4.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/motion/channel.rb +3 -3
- data/lib/motion/component/rendering.rb +8 -2
- data/lib/motion/component_connection.rb +3 -3
- data/lib/motion/element.rb +4 -0
- data/lib/motion/errors.rb +5 -2
- data/lib/motion/serializer.rb +14 -2
- data/lib/motion/test_helpers.rb +44 -3
- data/lib/motion/version.rb +1 -1
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff2870c4229fefaba7ff72f8275b969006a6b0db22144c234e5dd3554523a95d
|
4
|
+
data.tar.gz: 5c5488e3dd2ae17e8bd4db86c5daf64db3093bcf35729a2d185965cc84f8be27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af5d390212fac33bc5db249f23d9401b5ca5da3c2ef4edfd6a606d68ce5fa4fc8c5153b5e29ee2fb8b4a8d5c07e40aa543e1ef35cef0682c021675a24fcb7fed
|
7
|
+
data.tar.gz: 4418c496d43ea478b16c828538fc3a18850c8ba60d68646a715453ee47b80c9751aa1948df1c423002c4b19b223be115d12b9ed4be7ce28cc14db611272d4f04
|
data/lib/motion/channel.rb
CHANGED
@@ -13,7 +13,7 @@ module Motion
|
|
13
13
|
ACTION_METHODS = Set.new(["process_motion"]).freeze
|
14
14
|
private_constant :ACTION_METHODS
|
15
15
|
|
16
|
-
# Don't use the ActionCable
|
16
|
+
# Don't use the ActionCable heuristic for deciding what actions can be
|
17
17
|
# called from JavaScript. Instead, hard-code the list so we can make other
|
18
18
|
# methods public without worrying about them being called from JavaScript.
|
19
19
|
def self.action_methods
|
@@ -66,7 +66,7 @@ module Motion
|
|
66
66
|
|
67
67
|
def synchronize
|
68
68
|
component_connection.if_render_required do |component|
|
69
|
-
transmit(renderer.render(component))
|
69
|
+
transmit(renderer.render(component, layout: nil))
|
70
70
|
end
|
71
71
|
|
72
72
|
streaming_from component_connection.broadcasts,
|
@@ -84,7 +84,7 @@ module Motion
|
|
84
84
|
@log_helper ||= LogHelper.for_channel(self)
|
85
85
|
end
|
86
86
|
|
87
|
-
# Memoize the renderer on the connection so that it can be shared
|
87
|
+
# Memoize the renderer on the connection so that it can be shared across
|
88
88
|
# all components. `ActionController::Renderer` is already thread-safe and
|
89
89
|
# designed to be reused.
|
90
90
|
def renderer
|
@@ -23,9 +23,14 @@ module Motion
|
|
23
23
|
@controller
|
24
24
|
@request
|
25
25
|
@tag_builder
|
26
|
+
|
27
|
+
@asset_resolver_strategies
|
28
|
+
@assets_environment
|
26
29
|
].freeze
|
27
30
|
|
28
|
-
|
31
|
+
STATE_IVAR_OBFUSCATION_PREFIX = "@__vc_"
|
32
|
+
|
33
|
+
private_constant :STATE_EXCLUDED_IVARS, :STATE_IVAR_OBFUSCATION_PREFIX
|
29
34
|
|
30
35
|
def rerender!
|
31
36
|
@_awaiting_forced_rerender = true
|
@@ -53,7 +58,7 @@ module Motion
|
|
53
58
|
view_context.capture { super }
|
54
59
|
}
|
55
60
|
|
56
|
-
raise RenderAborted, self
|
61
|
+
raise RenderAborted, self unless html
|
57
62
|
|
58
63
|
Motion.markup_transformer.add_state_to_html(self, html)
|
59
64
|
end
|
@@ -66,6 +71,7 @@ module Motion
|
|
66
71
|
|
67
72
|
def marshal_dump
|
68
73
|
(instance_variables - STATE_EXCLUDED_IVARS)
|
74
|
+
.reject { |ivar| ivar.start_with? STATE_IVAR_OBFUSCATION_PREFIX }
|
69
75
|
.map { |ivar| [ivar, instance_variable_get(ivar)] }
|
70
76
|
.to_h
|
71
77
|
end
|
@@ -41,7 +41,7 @@ module Motion
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def process_motion(motion, event = nil)
|
44
|
-
timing("
|
44
|
+
timing("Processed #{motion}") do
|
45
45
|
component.process_motion(motion, event)
|
46
46
|
end
|
47
47
|
|
@@ -53,7 +53,7 @@ module Motion
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def process_broadcast(broadcast, message)
|
56
|
-
timing("
|
56
|
+
timing("Processed broadcast to #{broadcast}") do
|
57
57
|
component.process_broadcast broadcast, message
|
58
58
|
end
|
59
59
|
|
@@ -65,7 +65,7 @@ module Motion
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def process_periodic_timer(timer)
|
68
|
-
timing("
|
68
|
+
timing("Processed periodic timer #{timer}") do
|
69
69
|
component.process_periodic_timer timer
|
70
70
|
end
|
71
71
|
|
data/lib/motion/element.rb
CHANGED
data/lib/motion/errors.rb
CHANGED
@@ -68,7 +68,7 @@ module Motion
|
|
68
68
|
class InvalidComponentStateError < ComponentError; end
|
69
69
|
|
70
70
|
class UnrepresentableStateError < InvalidComponentStateError
|
71
|
-
def initialize(component, cause)
|
71
|
+
def initialize(component, cause, failing_ivars)
|
72
72
|
super(
|
73
73
|
component,
|
74
74
|
"Some state prevented `#{component.class}` from being serialized " \
|
@@ -79,6 +79,9 @@ module Motion
|
|
79
79
|
"\n" \
|
80
80
|
"The specific error from `Marshal.dump` was: #{cause}\n" \
|
81
81
|
"\n" \
|
82
|
+
"unserializable ivars: #{failing_ivars.join(", ")}\n"\
|
83
|
+
"\n" \
|
84
|
+
"\n" \
|
82
85
|
"Hint: Ensure that any exotic state variables in " \
|
83
86
|
"`#{component.class}` are removed or replaced."
|
84
87
|
)
|
@@ -114,7 +117,7 @@ module Motion
|
|
114
117
|
"of the application to be mounted because new code with old state " \
|
115
118
|
"can lead to unpredictable and unsafe behavior.\n" \
|
116
119
|
"\n" \
|
117
|
-
"Hint: If you would like to allow this component to
|
120
|
+
"Hint: If you would like to allow this component to survive " \
|
118
121
|
"deployments, consider providing an alternative implimentation for " \
|
119
122
|
"`#{component.class}.upgrade_from`."
|
120
123
|
)
|
data/lib/motion/serializer.rb
CHANGED
@@ -61,10 +61,22 @@ module Motion
|
|
61
61
|
|
62
62
|
private
|
63
63
|
|
64
|
-
def dump(component)
|
64
|
+
def dump!(component)
|
65
65
|
Marshal.dump(component)
|
66
|
+
end
|
67
|
+
|
68
|
+
def dump(component)
|
69
|
+
dump!(component)
|
66
70
|
rescue TypeError => e
|
67
|
-
|
71
|
+
failing_ivars = []
|
72
|
+
|
73
|
+
component.marshal_dump.each do |ivar_name, ivar_value|
|
74
|
+
dump!(ivar_value)
|
75
|
+
rescue TypeError
|
76
|
+
failing_ivars << ivar_name
|
77
|
+
end
|
78
|
+
|
79
|
+
raise UnrepresentableStateError.new(component, e.message, failing_ivars)
|
68
80
|
end
|
69
81
|
|
70
82
|
def load(state)
|
data/lib/motion/test_helpers.rb
CHANGED
@@ -4,6 +4,14 @@ require "motion"
|
|
4
4
|
|
5
5
|
module Motion
|
6
6
|
module TestHelpers
|
7
|
+
class MockComponent < ViewComponent::Base
|
8
|
+
include Motion::Component
|
9
|
+
end
|
10
|
+
|
11
|
+
def callback_stub(method_name = :bound)
|
12
|
+
Motion::Callback.new(MockComponent.new, method_name)
|
13
|
+
end
|
14
|
+
|
7
15
|
def assert_motion(component, motion_name)
|
8
16
|
assert motion?(component, motion_name)
|
9
17
|
end
|
@@ -16,14 +24,47 @@ module Motion
|
|
16
24
|
component.motions.include?(motion_name.to_s)
|
17
25
|
end
|
18
26
|
|
19
|
-
def run_motion(component, motion_name)
|
27
|
+
def run_motion(component, motion_name, event = motion_event)
|
20
28
|
if block_given?
|
21
29
|
c = component.dup
|
22
|
-
c.process_motion(motion_name.to_s)
|
30
|
+
c.process_motion(motion_name.to_s, event)
|
23
31
|
yield c
|
24
32
|
else
|
25
|
-
component.process_motion(motion_name.to_s)
|
33
|
+
component.process_motion(motion_name.to_s, event)
|
26
34
|
end
|
27
35
|
end
|
36
|
+
|
37
|
+
def process_broadcast(component, method_name, msg)
|
38
|
+
callback = component.bind(method_name)
|
39
|
+
component.process_broadcast(callback.broadcast, msg)
|
40
|
+
end
|
41
|
+
|
42
|
+
def assert_timer(component, method_name, interval)
|
43
|
+
assert_equal interval, component.periodic_timers[method_name.to_s]
|
44
|
+
end
|
45
|
+
|
46
|
+
def refute_timer(component, method_name)
|
47
|
+
refute timer?(component, method_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def timer?(component, method_name)
|
51
|
+
component.periodic_timers.include?(method_name.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def motion_event(attributes = {})
|
55
|
+
Motion::Event.new(ActiveSupport::JSON.decode(attributes.to_json)).tap do |event|
|
56
|
+
set_form_data(event, attributes)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def set_form_data(event, attrs)
|
63
|
+
return event unless attrs.fetch(:element, nil)
|
64
|
+
|
65
|
+
form_data = attrs.dig(:element, :formData) || {}
|
66
|
+
params = ActionController::Parameters.new(form_data)
|
67
|
+
event.element.instance_variable_set(:@form_data, params)
|
68
|
+
end
|
28
69
|
end
|
29
70
|
end
|
data/lib/motion/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alec Larsen
|
8
8
|
- Drew Ulmer
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-06-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '5.
|
34
|
+
version: '5.2'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: '5.
|
41
|
+
version: '5.2'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: lz4-ruby
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,7 +102,7 @@ metadata:
|
|
102
102
|
source_code_uri: https://github.com/unabridged/motion
|
103
103
|
post_install_message: |
|
104
104
|
Friendly reminder: When updating the motion gem, don't forget to update the
|
105
|
-
NPM package as well (`bin/yarn add '@unabridged/motion@0.
|
105
|
+
NPM package as well (`bin/yarn add '@unabridged/motion@0.7.0'`).
|
106
106
|
rdoc_options: []
|
107
107
|
require_paths:
|
108
108
|
- lib
|
@@ -117,8 +117,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
117
|
- !ruby/object:Gem::Version
|
118
118
|
version: '0'
|
119
119
|
requirements: []
|
120
|
-
rubygems_version: 3.
|
121
|
-
signing_key:
|
120
|
+
rubygems_version: 3.1.6
|
121
|
+
signing_key:
|
122
122
|
specification_version: 4
|
123
123
|
summary: Reactive frontend UI components for Rails in pure Ruby.
|
124
124
|
test_files: []
|