Module: Importu::ConfigDSL

Included in:
Definition, Importer
Defined in:
lib/importu/config_dsl.rb

Overview

DSL methods for configuring importers.

These methods define your import specification: what fields to extract, how to convert them, where to persist, and what actions are allowed.

## Field Definition

  • #field - Define a single field with options

  • #fields - Define multiple fields at once

  • #converter - Create a custom converter

  • #convert_to - Reference a built-in or custom converter

## Persistence

  • #model - Connect to a model class for persistence

  • #find_by - Specify how to find existing records

  • #allow_actions - Control create/update permissions

  • #before_save - Hook to modify records before saving

## Source Configuration

  • #source - Configure source-specific options

Examples:

Complete importer definition

class BookImporter < Importu::Importer
  # Fields
  fields :title, :author
  field :isbn, label: "ISBN-10"
  field :pages, required: false, &convert_to(:integer)
  field :price, &convert_to(:decimal)

  # Persistence
  model "Book"
  allow_actions :create, :update
  find_by :isbn

  # Hooks
  before_save { object.title = object.title.titleize }
end

See Also:

Defined Under Namespace

Classes: ConverterStub

Instance Method Summary collapse

Instance Method Details

#allow_actions(*actions) ⇒ void

This method returns an undefined value.

Specifies which persistence actions are allowed during import.

Examples:

Allow only creating new records (default)

allow_actions :create

Allow both creating and updating

allow_actions :create, :update

Parameters:

  • actions (Array<Symbol>)

    the actions to allow (:create and/or :update)



66
67
68
69
70
# File 'lib/importu/config_dsl.rb', line 66

def allow_actions(*actions)
  @config = { **config,
    backend: { **config[:backend], allowed_actions: actions.compact }
  }
end

#before_save { ... } ⇒ void

This method returns an undefined value.

Defines a callback to execute just before saving a record.

The block is executed in the context of an AssignmentContext, which provides access to:

  • object: the model instance being saved

  • record: the converted record data

  • action: :create or :update

This is a backend hook. Backends may choose to honor it or ignore it. The ActiveRecord backend executes it after assigning field values but before calling save!.

Examples:

Normalize title before saving

before_save { object.title = object.title.titleize }

Set audit field

before_save { object.imported_at = Time.current }

Conditional logic based on action

before_save do
  object.created_by = "importer" if action == :create
  object.updated_by = "importer" if action == :update
end

Yields:

  • block to execute before saving

See Also:



265
266
267
268
269
# File 'lib/importu/config_dsl.rb', line 265

def before_save(&block)
  @config = { **config,
    backend: { **config[:backend], before_save: block }
  }
end

#configHash

Returns the current configuration hash for this importer.

Returns:

  • (Hash)

    the configuration hash



48
49
50
51
52
# File 'lib/importu/config_dsl.rb', line 48

def config
  @config ||= superclass.respond_to?(:config) \
    ? superclass.config
    : default_config
end

#convert_to(type, **options) ⇒ ConverterStub

Creates a converter reference for use with field definitions.

Examples:

Basic usage

field :pages, &convert_to(:integer)

With options

field :release_date, &convert_to(:date, format: "%Y-%m-%d")

Parameters:

  • type (Symbol)

    the converter type (:string, :integer, :date, etc.)

  • options (Hash)

    converter-specific options

Returns:



85
86
87
88
# File 'lib/importu/config_dsl.rb', line 85

def convert_to(type, **options)
  config[:converters].fetch(type) # validate converter exists
  ConverterStub.for(type, **options)
end

#converter(name) {|field_name, **options| ... } ⇒ void

This method returns an undefined value.

Defines a custom converter for use in field definitions.

Examples:

Simple converter

converter(:uppercase) do |name|
  value = raw(name)
  value.respond_to?(:upcase) ? value.upcase : value
end

Converter with options

converter(:varchar) do |name, length: 255|
  value = trimmed(name)
  value.nil? ? nil : String(value).slice(0, length)
end

Parameters:

  • name (Symbol)

    the converter name

Yields:

  • (field_name, **options)

    block that performs the conversion

Yield Parameters:

  • field_name (Symbol)

    the field being converted

  • options (Hash)

    any options passed to convert_to

Yield Returns:

  • the converted value



112
113
114
115
116
# File 'lib/importu/config_dsl.rb', line 112

def converter(name, &block)
  @config = { **config,
    converters: { **config[:converters], name => block }
  }
end

#field(name, **props) {|field_name| ... } ⇒ void

This method returns an undefined value.

Defines a single field with its configuration.

Examples:

Basic field

field :title

Field with label mapping

field :authors, label: "author"

Field with converter

field :pages, &convert_to(:integer)

Field with custom conversion block

field :authors do
  trimmed(:authors).to_s.split(", ")
end

Parameters:

  • name (Symbol)

    the field name (used as the key in record hashes)

  • props (Hash)

    field options

Options Hash (**props):

  • :label (String)

    the column/key name in source data (default: field name as string)

  • :required (Boolean)

    whether the field must be present (default: true)

  • :abstract (Boolean)

    whether the field is computed, not from source (default: false)

  • :default (Object)

    value to use when field is nil and not required

  • :create (Boolean)

    include this field when creating records (default: true)

  • :update (Boolean)

    include this field when updating records (default: true)

Yields:

  • (field_name)

    optional block for custom conversion logic



146
147
148
149
150
151
152
153
154
155
# File 'lib/importu/config_dsl.rb', line 146

def field(name, **props, &block)
  field = config[:fields].fetch(name, field_defaults(name))
  props[:converter] = block if block

  @config = { **config,
    fields: { **config[:fields],
      name => { **field, **props }
    }
  }
end

#fields(*names, **props) { ... } ⇒ void

This method returns an undefined value.

Defines multiple fields with the same configuration.

Examples:

Multiple fields

fields :title, :author, :isbn

Multiple fields with shared converter

fields :pages, :quantity, &convert_to(:integer)

Parameters:

  • names (Array<Symbol>)

    the field names

  • props (Hash)

    field options (see #field for available options)

Yields:

  • optional block for custom conversion (applied to all fields)



171
172
173
# File 'lib/importu/config_dsl.rb', line 171

def fields(*names, **props, &block)
  names.each {|name| field(name, **props, &block) }
end

#find_by(*field_groups) {|record| ... } ⇒ void

This method returns an undefined value.

Specifies how to find existing records for updates.

Examples:

Single field lookup

find_by :isbn

Multiple fields (all must match)

find_by :title, :author

Multiple field groups (tried in order)

find_by :isbn, [:title, :author]

Custom lookup block

find_by do |record|
  find_by(title: record[:title].downcase)
end

Parameters:

  • field_groups (Array<Symbol, Array<Symbol>>)

    fields to match against

Yields:

  • (record)

    optional block for custom lookup logic

Yield Parameters:



197
198
199
200
201
202
203
204
205
# File 'lib/importu/config_dsl.rb', line 197

def find_by(*field_groups, &block)
  finder_fields = [*field_groups, block].compact.map do |field_group|
    field_group.respond_to?(:call) ? field_group : Array(field_group)
  end

  @config = { **config,
    backend: { **config[:backend], finder_fields: finder_fields }
  }
end

#model(name, backend: nil) ⇒ void

This method returns an undefined value.

Associates the importer with a model class for persistence.

The backend can be:

  • nil or :auto - auto-detect from registered backends

  • :active_record - use ActiveRecord backend explicitly

  • Any other symbol registered with Importu::Backends.registry

Examples:

Basic usage

model "Book"

With explicit backend

model "Book", backend: :active_record

With auto-detection (default behavior)

model "Book", backend: :auto

Parameters:

  • name (String, Class)

    the model class or class name

  • backend (Symbol, nil) (defaults to: nil)

    the backend to use (:active_record, :auto, or nil)

See Also:



230
231
232
233
234
# File 'lib/importu/config_dsl.rb', line 230

def model(name, backend: nil)
  @config = { **config,
    backend: { **config[:backend], name: backend, model: name }
  }
end

#source(type, **props) ⇒ void

This method returns an undefined value.

Configures source-specific options.

Examples:

XML source with xpath

source :xml, records_xpath: "//book"

CSV source with custom delimiter

source :csv, col_sep: "\t"

Parameters:

  • type (Symbol)

    the source type (:csv, :json, :xml, :ruby)

  • props (Hash)

    source-specific options



284
285
286
287
288
289
290
291
292
# File 'lib/importu/config_dsl.rb', line 284

def source(type, **props)
  source = config[:sources].fetch(type, {})

  @config = { **config,
    sources: { **config[:sources],
      type => { **source, **props }
    }
  }
end