Module: Vident2::Internals::Resolver Private
- Defined in:
- lib/vident2/internals/resolver.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Resolves Declarations + instance state into a Draft of typed Stimulus::* values. The implied controller seeds first (unless ‘no_stimulus_controller`); prop and root_element_attributes paths both APPEND.
Two entry points:
`call` — pure; returns a new Draft. Use `:static` or `:all`.
`resolve_procs_into` — mutates an existing Draft. Called at render
time so DSL procs can reach `helpers` /
`view_context` (not wired at `after_initialize`).
Phases: ‘:static` skips anything with a `when_proc` or top-level Proc in args; `:procs` processes only those; `:all` does everything.
Procs nested inside a Hash descriptor (‘action(method: -> { … })`) escape the gate — unsupported shape; use the fluent builder or a top-level Proc.
Class Method Summary collapse
-
.absorb_input(draft, kind, input, instance, implied, phase:) ⇒ Object
private
Fold a prop / root_element_attributes value into the Draft.
- .absorb_one(kind_meta, entry, instance, implied) ⇒ Object private
- .absorb_root_element_attributes(draft, instance, implied, phase:) ⇒ Object private
- .absorb_stimulus_props(draft, instance, implied, phase:) ⇒ Object private
- .build_implied_controller(instance) ⇒ Object private
- .call(declarations, instance, phase: :all) ⇒ Object private
- .gated_out?(when_proc, instance) ⇒ Boolean private
-
.instance_id(instance) ⇒ Object
private
Raw ivar — calling ‘#id` would trigger auto-generation, and outlet auto-selectors include the `#<id>` prefix only when the user explicitly set one.
- .instance_ivar(instance, name) ⇒ Object private
- .key_for_parse(key) ⇒ Object private
-
.meta_for_controller(meta) ⇒ Object
private
Controller parse takes ‘as:` as a kwarg, not a positional.
- .parse_entry(kind_meta, entry, implied:, component_id:) ⇒ Object private
- .parse_single(value_class, args, implied:, component_id:) ⇒ Object private
-
.phase_allows?(is_proc, phase) ⇒ Boolean
private
Element-level gate (raw boolean; parallels Declaration-level ‘phase_matches?`).
-
.phase_matches?(decl, phase) ⇒ Boolean
private
Declaration-level phase gate.
- .read_prop(instance, name) ⇒ Object private
-
.resolve_args(args, instance) ⇒ Object
private
Evaluate proc args in the instance binding.
- .resolve_declarations(draft, declarations, instance, implied, phase:) ⇒ Object private
- .resolve_keyed(draft, kind, entries, instance, phase:) ⇒ Object private
- .resolve_keyed_scalars(draft, kind, entries, instance, implied, value_class, phase:) ⇒ Object private
- .resolve_keyed_values(draft, declarations, instance, implied, phase:) ⇒ Object private
- .resolve_positional(draft, kind, entries, instance, phase:) ⇒ Object private
-
.resolve_procs_into(draft, declarations, instance) ⇒ Object
private
Caller owns idempotence (Component uses ‘@__vident2_procs_resolved`).
-
.resolve_value_meta(decl, instance) ⇒ Object
private
Values accept the raw in args (proc or literal) or meta (‘static:`).
- .seed_implied_controller(draft, instance) ⇒ Object private
-
.splat_single_array(args) ⇒ Object
private
If ‘args` is a single Array element, unwrap it — positional kinds treat Array values as the singular parser’s arg tuple.
Class Method Details
.absorb_input(draft, kind, input, instance, implied, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Fold a prop / root_element_attributes value into the Draft. Each Hash value / Array element may be a Proc; phase-gated.
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/vident2/internals/resolver.rb', line 186 def absorb_input(draft, kind, input, instance, implied, phase:) return if input.nil? = Registry.fetch(kind) case input when Hash input.each do |key, raw| is_proc = raw.is_a?(Proc) next unless phase_allows?(is_proc, phase) absorbed = is_proc ? instance.instance_exec(&raw) : raw next if absorbed.nil? if .keyed parsed = .value_class.parse(key, absorbed, implied: implied, component_id: instance_id(instance)) draft.public_send(:"add_#{kind}", parsed) else parsed = parse_entry(, [key, absorbed], implied: implied, component_id: instance_id(instance)) draft.public_send(:"add_#{kind}", parsed) if parsed end end when Array input.each do |entry| is_proc = entry.is_a?(Proc) next unless phase_allows?(is_proc, phase) parsed = absorb_one(, entry, instance, implied) draft.public_send(:"add_#{kind}", parsed) if parsed end else is_proc = input.is_a?(Proc) return unless phase_allows?(is_proc, phase) parsed = absorb_one(, input, instance, implied) draft.public_send(:"add_#{kind}", parsed) if parsed end end |
.absorb_one(kind_meta, entry, instance, implied) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
229 230 231 232 233 234 235 |
# File 'lib/vident2/internals/resolver.rb', line 229 def absorb_one(, entry, instance, implied) entry = instance.instance_exec(&entry) if entry.is_a?(Proc) return nil if entry.nil? return entry if entry.is_a?(.value_class) parse_entry(, entry, implied: implied, component_id: instance_id(instance)) end |
.absorb_root_element_attributes(draft, instance, implied, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/vident2/internals/resolver.rb', line 170 def absorb_root_element_attributes(draft, instance, implied, phase:) return unless instance.respond_to?(:resolved_root_element_attributes, true) attrs = instance.send(:resolved_root_element_attributes) return unless attrs.is_a?(Hash) && !attrs.empty? absorb_input(draft, :controllers, attrs[:stimulus_controllers], instance, implied, phase: phase) absorb_input(draft, :actions, attrs[:stimulus_actions], instance, implied, phase: phase) absorb_input(draft, :targets, attrs[:stimulus_targets], instance, implied, phase: phase) absorb_input(draft, :outlets, attrs[:stimulus_outlets], instance, implied, phase: phase) absorb_input(draft, :values, attrs[:stimulus_values], instance, implied, phase: phase) absorb_input(draft, :params, attrs[:stimulus_params], instance, implied, phase: phase) absorb_input(draft, :class_maps, attrs[:stimulus_classes], instance, implied, phase: phase) end |
.absorb_stimulus_props(draft, instance, implied, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
160 161 162 163 164 165 166 167 168 |
# File 'lib/vident2/internals/resolver.rb', line 160 def absorb_stimulus_props(draft, instance, implied, phase:) absorb_input(draft, :controllers, instance_ivar(instance, :@stimulus_controllers), instance, implied, phase: phase) absorb_input(draft, :actions, instance_ivar(instance, :@stimulus_actions), instance, implied, phase: phase) absorb_input(draft, :targets, instance_ivar(instance, :@stimulus_targets), instance, implied, phase: phase) absorb_input(draft, :outlets, instance_ivar(instance, :@stimulus_outlets), instance, implied, phase: phase) absorb_input(draft, :values, instance_ivar(instance, :@stimulus_values), instance, implied, phase: phase) absorb_input(draft, :params, instance_ivar(instance, :@stimulus_params), instance, implied, phase: phase) absorb_input(draft, :class_maps, instance_ivar(instance, :@stimulus_classes), instance, implied, phase: phase) end |
.build_implied_controller(instance) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
52 53 54 55 56 |
# File 'lib/vident2/internals/resolver.rb', line 52 def build_implied_controller(instance) path = instance.class.stimulus_identifier_path name = instance.class.stimulus_identifier ::Vident2::Stimulus::Controller.new(path: path, name: name) end |
.call(declarations, instance, phase: :all) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/vident2/internals/resolver.rb', line 29 def call(declarations, instance, phase: :all) raise ArgumentError, "use resolve_procs_into for phase: :procs" if phase == :procs draft = Draft.new implied = build_implied_controller(instance) seed_implied_controller(draft, instance) resolve_declarations(draft, declarations, instance, implied, phase: phase) absorb_stimulus_props(draft, instance, implied, phase: phase) absorb_root_element_attributes(draft, instance, implied, phase: phase) draft end |
.gated_out?(when_proc, instance) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
271 272 273 274 |
# File 'lib/vident2/internals/resolver.rb', line 271 def gated_out?(when_proc, instance) return false unless when_proc !instance.instance_exec(&when_proc) end |
.instance_id(instance) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Raw ivar — calling ‘#id` would trigger auto-generation, and outlet auto-selectors include the `#<id>` prefix only when the user explicitly set one.
293 294 295 296 297 |
# File 'lib/vident2/internals/resolver.rb', line 293 def instance_id(instance) return nil unless instance.instance_variable_defined?(:@id) raw = instance.instance_variable_get(:@id) raw.presence end |
.instance_ivar(instance, name) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
285 286 287 288 |
# File 'lib/vident2/internals/resolver.rb', line 285 def instance_ivar(instance, name) return nil unless instance.instance_variable_defined?(name) instance.instance_variable_get(name) end |
.key_for_parse(key) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
280 |
# File 'lib/vident2/internals/resolver.rb', line 280 def key_for_parse(key) = key |
.meta_for_controller(meta) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Controller parse takes ‘as:` as a kwarg, not a positional.
283 |
# File 'lib/vident2/internals/resolver.rb', line 283 def () = .slice(:as) |
.parse_entry(kind_meta, entry, implied:, component_id:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/vident2/internals/resolver.rb', line 237 def parse_entry(, entry, implied:, component_id:) case entry when Hash if .keyed first_key, first_val = entry.first .value_class.parse(first_key, first_val, implied: implied, component_id: component_id) else .value_class.parse(entry, implied: implied, component_id: component_id) end when Array .value_class.parse(*entry, implied: implied, component_id: component_id) else .value_class.parse(entry, implied: implied, component_id: component_id) end end |
.parse_single(value_class, args, implied:, component_id:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
276 277 278 |
# File 'lib/vident2/internals/resolver.rb', line 276 def parse_single(value_class, args, implied:, component_id:) value_class.parse(*args, implied: implied, component_id: component_id) end |
.phase_allows?(is_proc, phase) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Element-level gate (raw boolean; parallels Declaration-level ‘phase_matches?`).
221 222 223 224 225 226 227 |
# File 'lib/vident2/internals/resolver.rb', line 221 def phase_allows?(is_proc, phase) case phase when :all then true when :static then !is_proc when :procs then is_proc end end |
.phase_matches?(decl, phase) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Declaration-level phase gate. Nested Procs inside Hash args aren’t inspected — see module docstring.
154 155 156 157 158 |
# File 'lib/vident2/internals/resolver.rb', line 154 def phase_matches?(decl, phase) return true if phase == :all has_proc = decl.when_proc || decl.args.any? { |a| a.is_a?(Proc) } (phase == :procs) ? has_proc : !has_proc end |
.read_prop(instance, name) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
299 300 301 302 303 |
# File 'lib/vident2/internals/resolver.rb', line 299 def read_prop(instance, name) ivar = :"@#{name}" return nil unless instance.instance_variable_defined?(ivar) instance.instance_variable_get(ivar) end |
.resolve_args(args, instance) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Evaluate proc args in the instance binding. Only nil drops —false / blank strings / empty collections reach the parser.
255 256 257 258 259 |
# File 'lib/vident2/internals/resolver.rb', line 255 def resolve_args(args, instance) resolved = args.map { |arg| arg.is_a?(Proc) ? instance.instance_exec(&arg) : arg } return nil if resolved.any?(&:nil?) resolved end |
.resolve_declarations(draft, declarations, instance, implied, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/vident2/internals/resolver.rb', line 63 def resolve_declarations(draft, declarations, instance, implied, phase:) resolve_positional(draft, :controllers, declarations.controllers, instance, phase: phase) do |args, , _inst| ::Vident2::Stimulus::Controller.parse(*args, implied: implied, **()) end resolve_positional(draft, :actions, declarations.actions, instance, phase: phase) do |args, , _inst| parse_single(::Vident2::Stimulus::Action, args, implied: implied, component_id: instance_id(instance)) end resolve_positional(draft, :targets, declarations.targets, instance, phase: phase) do |args, , _inst| parse_single(::Vident2::Stimulus::Target, args, implied: implied, component_id: instance_id(instance)) end resolve_keyed(draft, :outlets, declarations.outlets, instance, phase: phase) do |key, args, | parsed_args = [key_for_parse(key), *args] parse_single(::Vident2::Stimulus::Outlet, parsed_args, implied: implied, component_id: instance_id(instance)) end resolve_keyed_values(draft, declarations, instance, implied, phase: phase) resolve_keyed_scalars(draft, :params, declarations.params, instance, implied, ::Vident2::Stimulus::Param, phase: phase) resolve_keyed_scalars(draft, :class_maps, declarations.class_maps, instance, implied, ::Vident2::Stimulus::ClassMap, phase: phase) end |
.resolve_keyed(draft, kind, entries, instance, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/vident2/internals/resolver.rb', line 104 def resolve_keyed(draft, kind, entries, instance, phase:) entries.each do |(key, decl)| next unless phase_matches?(decl, phase) next if gated_out?(decl.when_proc, instance) args = resolve_args(decl.args, instance) next if args.nil? parsed = yield(key, args, decl.) draft.public_send(:"add_#{kind}", parsed) if parsed end end |
.resolve_keyed_scalars(draft, kind, entries, instance, implied, value_class, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
142 143 144 145 146 147 148 149 150 |
# File 'lib/vident2/internals/resolver.rb', line 142 def resolve_keyed_scalars(draft, kind, entries, instance, implied, value_class, phase:) entries.each do |(key, decl)| next unless phase_matches?(decl, phase) next if gated_out?(decl.when_proc, instance) raw = (decl, instance) next if raw.nil? draft.public_send(:"add_#{kind}", value_class.parse(key, raw, implied: implied)) end end |
.resolve_keyed_values(draft, declarations, instance, implied, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/vident2/internals/resolver.rb', line 115 def resolve_keyed_values(draft, declarations, instance, implied, phase:) declarations.values.each do |(key, decl)| next unless phase_matches?(decl, phase) next if gated_out?(decl.when_proc, instance) if decl.[:from_prop] raw = read_prop(instance, key) next if raw.nil? draft.add_values(::Vident2::Stimulus::Value.parse(key, raw, implied: implied)) next end raw = (decl, instance) next if raw.nil? draft.add_values(::Vident2::Stimulus::Value.parse(key, raw, implied: implied)) end # values_from_props is a plain Symbol list (no Declarations, so # phase_matches? doesn't apply). Ivar reads only; run once. return if phase == :procs declarations.values_from_props.each do |name| raw = read_prop(instance, name) next if raw.nil? draft.add_values(::Vident2::Stimulus::Value.parse(name, raw, implied: implied)) end end |
.resolve_positional(draft, kind, entries, instance, phase:) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/vident2/internals/resolver.rb', line 86 def resolve_positional(draft, kind, entries, instance, phase:) entries.each do |decl| next unless phase_matches?(decl, phase) next if gated_out?(decl.when_proc, instance) args = resolve_args(decl.args, instance) next if args.nil? args = splat_single_array(args) parsed = yield(args, decl., instance) draft.public_send(:"add_#{kind}", parsed) if parsed end end |
.resolve_procs_into(draft, declarations, instance) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Caller owns idempotence (Component uses ‘@__vident2_procs_resolved`).
44 45 46 47 48 49 50 |
# File 'lib/vident2/internals/resolver.rb', line 44 def resolve_procs_into(draft, declarations, instance) implied = build_implied_controller(instance) resolve_declarations(draft, declarations, instance, implied, phase: :procs) absorb_stimulus_props(draft, instance, implied, phase: :procs) absorb_root_element_attributes(draft, instance, implied, phase: :procs) draft end |
.resolve_value_meta(decl, instance) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Values accept the raw in args (proc or literal) or meta (‘static:`).
262 263 264 265 266 267 268 269 |
# File 'lib/vident2/internals/resolver.rb', line 262 def (decl, instance) return decl.[:static] if decl..key?(:static) return nil if decl.args.empty? raw = decl.args.first raw = instance.instance_exec(&raw) if raw.is_a?(Proc) raw end |
.seed_implied_controller(draft, instance) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
58 59 60 61 |
# File 'lib/vident2/internals/resolver.rb', line 58 def seed_implied_controller(draft, instance) return unless instance.class.stimulus_controller? draft.add_controllers(build_implied_controller(instance)) end |
.splat_single_array(args) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
If ‘args` is a single Array element, unwrap it — positional kinds treat Array values as the singular parser’s arg tuple.
100 101 102 |
# File 'lib/vident2/internals/resolver.rb', line 100 def splat_single_array(args) (args.size == 1 && args[0].is_a?(Array)) ? args[0] : args end |