view_component_reducible 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a699ce3503948db085a77d5d187e725157966bf53a132e9d9124a772db648f1c
4
- data.tar.gz: ba68826392cd3ea83ca6ceea8f8f753d893f013467d61eff20f3085fd40c9e0c
3
+ metadata.gz: 5505b895dc07055d3d09ad5e466316aadab92321fd2b8a71c3889cc1284059f2
4
+ data.tar.gz: 66757165853350bb660d16605c935ec5072eb01aedf4dfaf62419ab4d1af5439
5
5
  SHA512:
6
- metadata.gz: 9eca692a8a5b7185869237597cb79d199d4e1e036501f2c9c2574e40ea643e99535202f31fb44198a51e293e2fd5078adefd2e65756bd95fc8732917a688b892
7
- data.tar.gz: bfe0b991478a5a8788f2b2f9c69f7705d5ad9bf1de828d76d50c5b652a8d57bb23c18dfe883289bf231c54b77885e311c35485e9d4a7fc37f200b87d113033a8
6
+ metadata.gz: a5a98ecba5e6ac762086bce05b77409360708c91489d6bbd23bba626e9cc0f6ed1f06ee138b90bcb44c68c06e4b35f4474365ea4b5baae3600283e261e1b09aa
7
+ data.tar.gz: b56697564e122c374d7291cd1955678af2fb79ca307351b74f4c39043e7912bebab33d4f2ae17d26644a46a42a6f9781267be0db27601b5bbad14affe7fa9a3d
@@ -20,17 +20,59 @@ module ViewComponentReducible
20
20
  type = params.fetch('vcr_msg_type')
21
21
  payload_json = params['vcr_msg_payload']
22
22
  payload = payload_json && payload_json != '' ? JSON.parse(payload_json) : {}
23
- new(type:, payload:)
23
+ build(type:, payload:)
24
24
  end
25
25
 
26
- private
26
+ # Build a Msg with a normalized payload object.
27
+ # @param type [String, Symbol]
28
+ # @param payload [Object, nil]
29
+ # @return [ViewComponentReducible::Msg]
30
+ def self.build(type:, payload: nil)
31
+ return new(type:, payload:) if payload.is_a?(Data)
27
32
 
28
- def normalized_type
33
+ normalized = normalize_type(type)
34
+ new(type:, payload: self::Payload.from_hash(normalized, payload))
35
+ end
36
+
37
+ # @param type [String, Symbol]
38
+ # @return [Symbol]
39
+ def self.normalize_type(type)
29
40
  type.to_s
30
41
  .gsub(/([a-z\d])([A-Z])/, '\1_\2')
31
42
  .tr('-', '_')
32
43
  .downcase
33
44
  .to_sym
34
45
  end
46
+
47
+ private
48
+
49
+ def normalized_type
50
+ self.class.normalize_type(type)
51
+ end
52
+ end
53
+
54
+ class Msg
55
+ module Payload
56
+ Empty = Data.define
57
+ Value = Data.define(:value)
58
+
59
+ def self.from_hash(_type, payload)
60
+ payload_hash = payload.is_a?(Hash) ? payload.transform_keys(&:to_s) : nil
61
+
62
+ return Empty.new if payload.nil? || (payload.respond_to?(:empty?) && payload.empty?)
63
+ return Value.new(value: payload) unless payload_hash
64
+
65
+ build_generic(payload_hash)
66
+ end
67
+
68
+ def self.build_generic(payload_hash)
69
+ return Empty.new if payload_hash.empty?
70
+
71
+ keys = payload_hash.keys.map(&:to_sym)
72
+ klass = Data.define(*keys)
73
+ values = keys.to_h { |key| [key, payload_hash[key.to_s]] }
74
+ klass.new(**values)
75
+ end
76
+ end
35
77
  end
36
78
  end
@@ -48,34 +48,53 @@ module ViewComponentReducible
48
48
  schema = component_klass.vcr_state_schema
49
49
  state = schema.build_data(env['data'])
50
50
 
51
- new_state = component.reduce(state, msg)
52
- env['data'] = normalize_state(new_state, schema)
53
- effects = build_effects(component, schema, env['data'], msg)
51
+ reducer_result = component.reduce(state, msg)
52
+ reduced_state, reducer_effects = case reducer_result
53
+ in state_only unless reducer_result.is_a?(Array)
54
+ [state_only, []]
55
+ in [state_only]
56
+ [state_only, []]
57
+ in [state_only, *effects]
58
+ [state_only, effects]
59
+ end
60
+ env['data'] = normalize_state(reduced_state, schema)
61
+ effects = normalize_effects(reducer_effects) + normalize_effects(build_effects(component, schema, env['data'],
62
+ msg))
54
63
 
55
64
  run_effects(component_klass, env, effects, controller)
56
65
  end
57
66
 
58
67
  def run_effects(component_klass, env, effects, controller)
59
- return env if effects.nil? || effects.empty?
68
+ effects_queue = normalize_effects(effects).dup
69
+ return env if effects_queue.empty?
60
70
 
61
- effects_queue = effects.dup
62
71
  steps = 0
63
72
 
64
73
  while (eff = effects_queue.shift)
65
74
  steps += 1
66
75
  raise 'Too many effect steps' if steps > MAX_EFFECT_STEPS
67
76
 
68
- follow_msg = eff.call(controller: controller, envelope: env)
77
+ follow_msg = resolve_effect_msg(eff, controller, env)
69
78
  next unless follow_msg
79
+ raise ArgumentError, 'Effect must return a Msg' unless follow_msg.is_a?(Msg)
70
80
 
71
81
  component = component_klass.new(vcr_envelope: env)
72
82
  schema = component_klass.vcr_state_schema
73
83
  state = schema.build_data(env['data'])
74
84
 
75
- new_state = component.reduce(state, follow_msg)
76
- env['data'] = normalize_state(new_state, schema)
77
- new_effects = build_effects(component, schema, env['data'], follow_msg)
78
- effects_queue.concat(Array(new_effects))
85
+ reducer_result = component.reduce(state, follow_msg)
86
+ reduced_state, reducer_effects = case reducer_result
87
+ in state_only unless reducer_result.is_a?(Array)
88
+ [state_only, []]
89
+ in [state_only]
90
+ [state_only, []]
91
+ in [state_only, *effects]
92
+ [state_only, effects]
93
+ end
94
+ env['data'] = normalize_state(reduced_state, schema)
95
+ new_effects = normalize_effects(reducer_effects) + normalize_effects(build_effects(component, schema,
96
+ env['data'], follow_msg))
97
+ effects_queue.concat(new_effects)
79
98
  end
80
99
 
81
100
  env
@@ -110,6 +129,17 @@ module ViewComponentReducible
110
129
  Array(component.effects(state, msg))
111
130
  end
112
131
 
132
+ def normalize_effects(effects)
133
+ Array(effects).compact
134
+ end
135
+
136
+ def resolve_effect_msg(effect, controller, env)
137
+ return effect if effect.is_a?(Msg)
138
+ return effect.call(controller: controller, envelope: env) if effect.respond_to?(:call)
139
+
140
+ raise ArgumentError, 'Effect must respond to #call or be a Msg'
141
+ end
142
+
113
143
  def deep_dup(obj)
114
144
  Marshal.load(Marshal.dump(obj))
115
145
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ViewComponentReducible
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component_reducible
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - manabeai