Class: LcpRuby::Dsl::PresenterBuilder

Inherits:
Object
  • Object
show all
Includes:
SourceLocationCapture
Defined in:
lib/lcp_ruby/dsl/presenter_builder.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SourceLocationCapture

capture_source_loc

Constructor Details

#initialize(name) ⇒ PresenterBuilder

Returns a new instance of PresenterBuilder.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 14

def initialize(name)
  @name = name.to_s
  @model_name = nil
  @label_value = nil
  @label_source_loc = nil
  @slug_value = nil
  @icon_value = nil
  @menu_position_value = nil
  @default_value = false
  @index_hash = nil
  @show_hash = nil
  @form_hash = nil
  @search_hash = nil
  @actions = []
  @options = {}
  @dialog_hash = nil
  @export_hash = nil
  @import_hash = nil
  @controller_value = nil
  @action_controllers_value = nil
  @record_aliases = {}
end

Class Method Details

.condition(&block) ⇒ Object

Builds a condition hash from a DSL block. Usage: condition = PresenterBuilder.condition { field(:status).eq(“active”) }



10
11
12
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 10

def self.condition(&block)
  ConditionBuilder.build(&block)
end

Instance Method Details

#action(name, type:, on:, **options) ⇒ Object

Flat actions



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 169

def action(name, type:, on:, **options)
  source_loc = capture_source_loc
  action_hash = {
    "name" => name.to_s,
    "type" => type.to_s
  }
  action_hash["_source_loc"] = source_loc if source_loc
  if options.key?(:label)
    action_hash["label"] = options[:label]
    action_hash["_label_source_loc"] = source_loc
  end
  action_hash["icon"] = options[:icon].to_s if options.key?(:icon)
  action_hash["confirm"] = options[:confirm].is_a?(Hash) ? HashUtils.stringify_deep(options[:confirm]) : options[:confirm] if options.key?(:confirm)
  action_hash["confirm_message"] = options[:confirm_message] if options.key?(:confirm_message)
  action_hash["style"] = options[:style].to_s if options.key?(:style)
  action_hash["dialog"] = HashUtils.stringify_deep(options[:dialog]) if options.key?(:dialog)
  action_hash["record"] = options[:record].to_s if options.key?(:record)
  action_hash["visible"] = options[:visible] if options.key?(:visible)
  action_hash["visible_when"] = resolve_condition(options[:visible_when]) if options.key?(:visible_when)
  action_hash["disable_when"] = resolve_condition(options[:disable_when]) if options.key?(:disable_when)

  # Batch action options
  %i[min_selection max_selection max_batch_records result_log select_all_filter
     execution background_threshold strategy].each do |key|
    action_hash[key.to_s] = options[key] if options.key?(key)
  end
  action_hash["fields"] = options[:fields].map(&:to_s) if options.key?(:fields)

  if options.key?(:batch)
    val = options[:batch]
    action_hash["batch"] = val.is_a?(Hash) ? HashUtils.stringify_deep(val) : val
  end

  # Pipeline / sugar attributes for single actions
  action_hash["pipeline"] = HashUtils.stringify_deep(options[:pipeline]) if options.key?(:pipeline)
  action_hash["transition"] = options[:transition].to_s if options.key?(:transition)
  action_hash["action"] = options[:action].to_s if options.key?(:action)

  @actions << { on: on.to_s, hash: action_hash }
end

#action_controllers(mapping) ⇒ Object



102
103
104
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 102

def action_controllers(mapping)
  @action_controllers_value = HashUtils.stringify_deep(mapping)
end

#controller(name) ⇒ Object



98
99
100
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 98

def controller(name)
  @controller_value = name.to_s
end

#default(value = true) ⇒ Object

B19 — Marks this presenter as the canonical link target for its model. Used by Presenter::Enrichment when the model has multiple presenters and a column/field uses ‘link: true` without a per-link `link_presenter:` override. Exactly one presenter per model may be marked default.



67
68
69
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 67

def default(value = true)
  @default_value = value == true
end

#dialog(size: nil, closable: nil, title_key: nil) ⇒ Object



110
111
112
113
114
115
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 110

def dialog(size: nil, closable: nil, title_key: nil)
  @dialog_hash = {}
  @dialog_hash["size"] = size.to_s if size
  @dialog_hash["closable"] = closable unless closable.nil?
  @dialog_hash["title_key"] = title_key.to_s if title_key
end

#embeddable(value = true) ⇒ Object



75
76
77
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 75

def embeddable(value = true)
  @options["embeddable"] = value
end

#empty_value(value) ⇒ Object



86
87
88
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 86

def empty_value(value)
  @options["empty_value"] = value
end

#export(formats: nil, max_records: nil, save_history: nil, fields: nil, csv_delimiter: nil) ⇒ Object



117
118
119
120
121
122
123
124
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 117

def export(formats: nil, max_records: nil, save_history: nil, fields: nil, csv_delimiter: nil)
  @export_hash = {}
  @export_hash["formats"] = formats.map(&:to_s) if formats
  @export_hash["max_records"] = max_records if max_records
  @export_hash["save_history"] = save_history unless save_history.nil?
  @export_hash["fields"] = fields.map(&:to_s) if fields
  @export_hash["csv_delimiter"] = csv_delimiter if csv_delimiter
end

#form(&block) ⇒ Object



152
153
154
155
156
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 152

def form(&block)
  builder = FormBuilder.new
  builder.instance_eval(&block)
  @form_hash = builder.to_hash
end

#form_action(name, **options) ⇒ Object

Form-specific action shorthand (routes to on: “form” context)



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 211

def form_action(name, **options)
  source_loc = capture_source_loc
  action_hash = { "name" => name.to_s }
  action_hash["type"] = options[:type].to_s if options.key?(:type)
  action_hash["_source_loc"] = source_loc if source_loc
  if options.key?(:label)
    action_hash["label"] = options[:label]
    action_hash["_label_source_loc"] = source_loc
  end
  if options.key?(:submitting_label)
    action_hash["submitting_label"] = options[:submitting_label]
    action_hash["_submitting_label_source_loc"] = source_loc
  end
  action_hash["icon"] = options[:icon].to_s if options.key?(:icon)
  action_hash["style"] = options[:style].to_s if options.key?(:style)
  if options.key?(:redirect)
    action_hash["redirect"] = options[:redirect].is_a?(Hash) ? HashUtils.stringify_deep(options[:redirect]) : options[:redirect].to_s
  end
  action_hash["only_on"] = options[:only_on].to_s if options.key?(:only_on)
  action_hash["confirm"] = options[:confirm].is_a?(Hash) ? HashUtils.stringify_deep(options[:confirm]) : options[:confirm] if options.key?(:confirm)
  action_hash["confirm_message"] = options[:confirm_message] if options.key?(:confirm_message)
  action_hash["set_fields"] = HashUtils.stringify_deep(options[:set_fields]) if options.key?(:set_fields)
  action_hash["pipeline"] = HashUtils.stringify_deep(options[:pipeline]) if options.key?(:pipeline)
  action_hash["transition"] = options[:transition].to_s if options.key?(:transition)
  action_hash["action"] = options[:action].to_s if options.key?(:action)
  action_hash["dialog_behavior"] = options[:dialog_behavior].to_s if options.key?(:dialog_behavior)
  action_hash["result"] = HashUtils.stringify_deep(options[:result]) if options.key?(:result)
  action_hash["position"] = options[:position].to_s if options.key?(:position)
  action_hash["visible_when"] = resolve_condition(options[:visible_when]) if options.key?(:visible_when)
  action_hash["disable_when"] = resolve_condition(options[:disable_when]) if options.key?(:disable_when)
  action_hash["only_roles"] = Array(options[:only_roles]).map(&:to_s) if options.key?(:only_roles)
  action_hash["except_roles"] = Array(options[:except_roles]).map(&:to_s) if options.key?(:except_roles)

  @actions << { on: "form", hash: action_hash }
end

#icon(value) ⇒ Object



51
52
53
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 51

def icon(value)
  @icon_value = value.to_s
end

#import(formats: nil, max_rows: nil, max_file_size: nil, csv_delimiter: nil, csv_encoding: nil, parsing: nil, nested_associations: nil, nested_blank_strategy: nil) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 126

def import(formats: nil, max_rows: nil, max_file_size: nil, csv_delimiter: nil, csv_encoding: nil, parsing: nil,
           nested_associations: nil, nested_blank_strategy: nil)
  @import_hash = {}
  @import_hash["formats"] = formats.map(&:to_s) if formats
  @import_hash["max_rows"] = max_rows if max_rows
  @import_hash["max_file_size"] = max_file_size if max_file_size
  @import_hash["csv_delimiter"] = csv_delimiter if csv_delimiter
  @import_hash["csv_encoding"] = csv_encoding.to_s if csv_encoding
  @import_hash["parsing"] = HashUtils.stringify_deep(parsing) if parsing
  @import_hash["nested_associations"] = nested_associations.map(&:to_s) if nested_associations
  @import_hash["nested_blank_strategy"] = nested_blank_strategy.to_s if nested_blank_strategy
end

#index(&block) ⇒ Object

View blocks



140
141
142
143
144
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 140

def index(&block)
  builder = IndexBuilder.new
  builder.instance_eval(&block)
  @index_hash = builder.to_hash
end

#label(value) ⇒ Object



42
43
44
45
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 42

def label(value)
  @label_value = value.to_s
  @label_source_loc = capture_source_loc
end

#max_inline_actions(value) ⇒ Object



90
91
92
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 90

def max_inline_actions(value)
  @options["max_inline_actions"] = value.to_i
end

#15 — Position hint for the auto-created view group when this is the only presenter on the model. Lifts the entry out of the alphabetical 900+index tier into a configurator-controlled position. Ignored when an explicit view group YAML exists for the model.



59
60
61
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 59

def menu_position(value)
  @menu_position_value = value.to_i
end

#model(value) ⇒ Object

Top-level setters



38
39
40
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 38

def model(value)
  @model_name = value.to_s
end

#read_only(value = true) ⇒ Object



71
72
73
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 71

def read_only(value = true)
  @options["read_only"] = value
end

#record_alias(name, **opts) ⇒ Object



106
107
108
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 106

def record_alias(name, **opts)
  @record_aliases[name.to_s] = HashUtils.stringify_deep(opts)
end

#redirect_after(create: nil, update: nil) ⇒ Object



79
80
81
82
83
84
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 79

def redirect_after(create: nil, update: nil)
  ra = {}
  ra["create"] = create.to_s if create
  ra["update"] = update.to_s if update
  @options["redirect_after"] = ra
end

#scope(value) ⇒ Object



94
95
96
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 94

def scope(value)
  @options["scope"] = value.to_s
end

#search(enabled: nil, &block) ⇒ Object



158
159
160
161
162
163
164
165
166
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 158

def search(enabled: nil, &block)
  if block
    builder = SearchBuilder.new
    builder.instance_eval(&block)
    @search_hash = builder.to_hash
  elsif !enabled.nil?
    @search_hash = { "enabled" => enabled }
  end
end

#show(&block) ⇒ Object



146
147
148
149
150
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 146

def show(&block)
  builder = ShowBuilder.new
  builder.instance_eval(&block)
  @show_hash = builder.to_hash
end

#slug(value) ⇒ Object



47
48
49
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 47

def slug(value)
  @slug_value = value.to_s
end

#to_hashObject



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 247

def to_hash
  hash = { "name" => @name }
  hash["model"] = @model_name if @model_name
  hash["label"] = @label_value if @label_value
  hash["_label_source_loc"] = @label_source_loc if @label_source_loc
  hash["slug"] = @slug_value if @slug_value
  hash["icon"] = @icon_value if @icon_value
  hash["menu_position"] = @menu_position_value if @menu_position_value
  hash["default"] = true if @default_value
  hash["record_aliases"] = @record_aliases unless @record_aliases.empty?

  hash["index"] = @index_hash if @index_hash
  hash["show"] = @show_hash if @show_hash
  hash["form"] = @form_hash if @form_hash
  hash["search"] = @search_hash if @search_hash
  hash["dialog"] = @dialog_hash if @dialog_hash
  hash["export"] = @export_hash if @export_hash
  hash["import"] = @import_hash if @import_hash

  unless @actions.empty?
    hash["actions"] = build_actions_hash
  end

  hash["controller"] = @controller_value if @controller_value
  hash["action_controllers"] = @action_controllers_value if @action_controllers_value

  # Options are stored at the top level for PresenterDefinition.from_hash
  @options.each { |k, v| hash[k] = v }

  hash
end

#to_hash_with_parent(parent_hash) ⇒ Object

Merge this builder’s output on top of a parent hash. Keys defined by the child replace the parent’s values entirely (section-level replace).



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 285

def to_hash_with_parent(parent_hash)
  child_hash = to_hash
  merged = parent_hash.deep_dup

  # `default: true` is intrinsic to a single presenter — never inherits.
  # The validator enforces exactly one default per model; auto-propagation
  # via `inherits:` would always violate that.
  merged.delete("default")

  # Always override these from child if defined
  %w[name label slug icon default record_aliases read_only embeddable redirect_after empty_value scope max_inline_actions controller action_controllers].each do |key|
    merged[key] = child_hash[key] if child_hash.key?(key)
  end

  # Section-level replace: child replaces parent entirely for these keys
  %w[index show form search actions dialog export import].each do |key|
    merged[key] = child_hash[key] if child_hash.key?(key)
  end

  # Model is always from parent unless child overrides
  merged["model"] = child_hash["model"] if child_hash.key?("model")

  merged
end

#to_yamlObject



279
280
281
# File 'lib/lcp_ruby/dsl/presenter_builder.rb', line 279

def to_yaml
  { "presenter" => to_hash }.to_yaml
end