Class: Eco::API::UseCases::GraphQL::Samples::Pages::Template::CommandEmitter

Inherits:
Object
  • Object
show all
Defined in:
lib/eco/api/usecases/graphql/samples/pages/template/command_emitter.rb

Overview

Declarative build-from-scratch emitter for template (workflow) structure.

Mirrors the shape of the location diff->commands engine (samples/location/command), but the id-threading is placeholder-based, not post-hoc newId-remap: each new node is given a client-chosen placeholderId, and later commands in the SAME batch reference it. The gem's executeWorkflowCommands resolves placeholders intra-batch. See the gem's PHASE0-FINDINGS.md.

Commands are emitted in dependency order via depth-first DSL evaluation: addStage -> (per section) addSection, addStageSection -> (per field) addField -> (per option) addSelectFieldOption ; then forces: addForce -> (per binding) addBinding.

Usage: emitter = CommandEmitter.new emitter.stage(name: 'Report', ordering: 0) do |stage| stage.section(layout: 'content') do |section| section.field(label: 'Notes', field_type: 'plain_text') section.field(label: 'Risk', field_type: 'select') do |field| field.option(label: 'High', weight: 10) end end end emitter.commands # => ordered Array of FINAL built { commandKey => kwargs } commands

The output is fed DIRECTLY to graphql.template.create(commands:) / update(model, commands:). It is already built via WorkflowCommand.build — do NOT re-run it through build_commands (that normaliser is for hand-authored raw specs and is non-idempotent for key-renaming commands such as addSelectFieldOption: data_field_id -> dataFieldId).

Defined Under Namespace

Classes: FieldBuilder, ForceBuilder, SectionBuilder, StageBuilder

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCommandEmitter

Returns a new instance of CommandEmitter.



31
32
33
34
# File 'lib/eco/api/usecases/graphql/samples/pages/template/command_emitter.rb', line 31

def initialize
  @commands = []
  @counters = Hash.new(0)
end

Instance Attribute Details

#commandsArray<Hash> (readonly)

Returns ordered command specs, each { commandKey => kwargs }.

Returns:

  • (Array<Hash>)

    ordered command specs, each { commandKey => kwargs }



37
38
39
# File 'lib/eco/api/usecases/graphql/samples/pages/template/command_emitter.rb', line 37

def commands
  @commands
end

Instance Method Details

#allocate(kind) ⇒ Object

Allocate the next placeholder id for a node kind (:stg, :sec, :fld, :frc, :bnd).



59
60
61
# File 'lib/eco/api/usecases/graphql/samples/pages/template/command_emitter.rb', line 59

def allocate(kind)
  "#{kind}#{@counters[kind] += 1}"
end

#emit(command_key, **kwargs) ⇒ Object

Build + append one command via the gem's WorkflowCommand contract. The gem constant is resolved lazily (at call time, not load time) — the gem's GraphQL namespace is not yet loaded while this file is being required.



66
67
68
# File 'lib/eco/api/usecases/graphql/samples/pages/template/command_emitter.rb', line 66

def emit(command_key, **kwargs)
  @commands << Ecoportal::API::GraphQL::Input::WorkflowCommand.build(command_key, **kwargs)
end

#force(name:, custom_script: nil, url: nil, content_b64: nil, &block) ⇒ Object

Declare a force at template level. Yields a ForceBuilder for bindings.



48
49
50
51
52
53
54
# File 'lib/eco/api/usecases/graphql/samples/pages/template/command_emitter.rb', line 48

def force(name:, custom_script: nil, url: nil, content_b64: nil, &block)
  placeholder = allocate(:frc)
  emit(:addForce, placeholderId: placeholder, name: name, customScript: custom_script,
                  url: url, contentB64: content_b64)
  ForceBuilder.new(self, placeholder).tap { |b| block&.call(b) }
  placeholder
end

#stage(name:, ordering: nil, &block) ⇒ Object

Declare a stage. Yields a StageBuilder for nested sections.



40
41
42
43
44
45
# File 'lib/eco/api/usecases/graphql/samples/pages/template/command_emitter.rb', line 40

def stage(name:, ordering: nil, &block)
  placeholder = allocate(:stg)
  emit(:addStage, placeholderId: placeholder, name: name, ordering: ordering)
  StageBuilder.new(self, placeholder).tap { |b| block&.call(b) }
  placeholder
end