Module: Evolvable::ClassMethods

Defined in:
lib/evolvable.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#cluster_configObject (readonly)

Returns the value of attribute cluster_config.



245
246
247
# File 'lib/evolvable.rb', line 245

def cluster_config
  @cluster_config
end

#gene_configObject (readonly)

Returns the value of attribute gene_config.



245
246
247
# File 'lib/evolvable.rb', line 245

def gene_config
  @gene_config
end

Instance Method Details

#after_evolution(population) ⇒ Object

Runs after evolution.



297
# File 'lib/evolvable.rb', line 297

def after_evolution(population); end

#before_evaluation(population) ⇒ Object

Called before evaluation.



273
# File 'lib/evolvable.rb', line 273

def before_evaluation(population); end

#before_evolution(population) ⇒ Object

Runs after evaluation and before evolution.

Examples:

class Melody
  include Evolvable

  # Play the best melody from each generation
  def self.before_evolution(population)
    population.best_evolvable.play
  end

  # ...
end


291
# File 'lib/evolvable.rb', line 291

def before_evolution(population); end

#cluster(cluster_name, type:, **opts) ⇒ Object

The .cluster macro applies a pre-defined group of related genes.

Clusters promote code organization through:

  • Modularity: Define related genes once, reuse them
  • Organization: Group genes by function
  • Maintenance: Update in one place
  • Accessibility: Access via a single accessor

Examples:

UI Component with Styling Cluster

# Define a gene cluster for UI styling properties
class ColorSchemeCluster
  include Evolvable::GeneCluster

  gene :background_color, type: 'ColorGene', count: 1
  gene :text_color, type: 'ColorGene', count: 1
  gene :accent_color, type: 'ColorGene', count: 0..1
end

# Use the cluster in an evolvable UI component
class Button
  include Evolvable

  cluster :colors, type: ColorSchemeCluster
  gene :padding, type: PaddingGene, count: 1

  def render
    puts "Button with #{colors.count} colors"
    puts "Background: #{colors.background_color.hex_code}"
  end
end

Parameters:

  • cluster_name (Symbol)

    The name for accessing the cluster

  • type (Class, String)

    The class that defines the cluster

  • opts (Hash)

    Optional arguments passed to the cluster initializer



234
235
236
237
238
239
240
241
242
243
# File 'lib/evolvable.rb', line 234

def cluster(cluster_name, type:, **opts)
  recipe = type.is_a?(String) ? Object.const_get(type) : type
  unless recipe.respond_to?(:apply_cluster)
    raise ArgumentError, "#{recipe} cannot apply a gene cluster"
  end

  recipe.apply_cluster(self, cluster_name, **opts)

  define_method(cluster_name) { find_gene_cluster(cluster_name) }
end

#gene(name, type:, count: 1, cluster: nil) ⇒ Object

The .gene macro defines traits that can mutate and evolve over time. Syntactically similar to ActiveRecord-style macros, it sets up the genetic structure of your model.

Key features:

  • Fixed or variable gene counts
  • Automatic accessor methods
  • Optional clustering for related genes

Examples:

Basic gene definition

class Melody
  include Evolvable

  gene :notes, type: NoteGene, count: 4..16 # Can have 4-16 notes
  gene :instrument, type: InstrumentGene, count: 1

  def play
    instrument.play(notes)
  end
end

Parameters:

  • name (Symbol)

    The name of the gene

  • type (String, Class)

    The gene type or class name

  • count (Integer, Range) (defaults to: 1)

    Number or range of gene instances

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

    Optional cluster name for grouping related genes

Raises:



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/evolvable.rb', line 174

def gene(name, type:, count: 1, cluster: nil)
  raise Error, "Gene name '#{name}' is already defined" if @gene_config.key?(name)

  @gene_config[name] = { type: type, count: count }

  if (count.is_a?(Range) ? count.last : count) > 1
    define_method(name) { find_genes(name) }
  else
    define_method(name) { find_gene(name) }
  end

  if cluster
    raise Error, "Cluster name '#{cluster}' conflicts with an existing gene name" if @gene_config.key?(cluster)

    if @cluster_config[cluster]
      @cluster_config[cluster] << name
    else
      @cluster_config[cluster] = [name]
      define_method(cluster) { find_gene_cluster(cluster) }
    end
  end
end

#inherited(subclass) ⇒ void

This method returns an undefined value.

Ensures that subclasses inherit the gene and cluster configuration.

Parameters:

  • subclass (Class)

    The subclass that is inheriting from this class



263
264
265
266
267
# File 'lib/evolvable.rb', line 263

def inherited(subclass)
  super
  subclass.instance_variable_set(:@gene_config, @gene_config.dup)
  subclass.instance_variable_set(:@cluster_config, @cluster_config.dup)
end

#initialize_evolvableEvolvable

Override this method to customize how your evolvable instances are initialized. By default, simply calls new with no arguments.

Returns:



143
144
145
# File 'lib/evolvable.rb', line 143

def initialize_evolvable
  new
end

#new_evolvable(population: nil, genome: nil, generation_index: nil) ⇒ Object

Initializes a new instance. Accepts a population object, an array of gene objects, and the instance's population index. This method is useful for re-initializing instances and populations that have been saved.

It is not recommended that you override this method as it is used by Evolvable internals. If you need to customize how your instances are initialized you can override either of the following two "initialize_instance" methods.



130
131
132
133
134
135
# File 'lib/evolvable.rb', line 130

def new_evolvable(population: nil, genome: nil, generation_index: nil)
  evolvable = initialize_evolvable
  evolvable.make_evolvable(population: population, genome: genome, generation_index: generation_index)
  evolvable.after_initialize_evolvable
  evolvable
end

#new_gene_spaceEvolvable::GeneSpace

Creates a new gene space for this evolvable class. Used internally when initializing populations.

Returns:



253
254
255
# File 'lib/evolvable.rb', line 253

def new_gene_space
  GeneSpace.build(@gene_config, self)
end

#new_population(keyword_args = {}) ⇒ Object

Initializes a population with defaults that can be changed using the same named parameters as Population#initialize.



115
116
117
118
# File 'lib/evolvable.rb', line 115

def new_population(keyword_args = {})
  keyword_args[:evolvable_type] = self
  Population.new(**keyword_args)
end