Class: LSystem::ProductionAdapter

Inherits:
Object
  • Object
show all
Extended by:
Loggability
Defined in:
lib/l_system/production_adapter.rb

Overview

An adapter that connects method calls to an LSystem::RulesEngine’s generations.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeProductionAdapter

Create a new instance of the ProductionAdapter.



84
85
86
# File 'lib/l_system/production_adapter.rb', line 84

def initialize
	@production_map = self.class.production_map
end

Instance Attribute Details

#production_mapObject (readonly)

The map of symbols to production methods



95
96
97
# File 'lib/l_system/production_adapter.rb', line 95

def production_map
  @production_map
end

Class Method Details

.inherited(subclass) ⇒ Object

Inheritance callback – add class-instance variables to the subclass.



20
21
22
23
24
25
# File 'lib/l_system/production_adapter.rb', line 20

def self::inherited( subclass )
	super

	subclass.instance_variable_set( :@production_map, {} )
	subclass.instance_variable_set( :@callbacks, {} )
end

.on_finish(&block) ⇒ Object

Register a callback that will be called at the end of each new generation. It will be called with the result of the this generation, which will be nil if no #result callback is declared.



73
74
75
76
# File 'lib/l_system/production_adapter.rb', line 73

def self::on_finish( &block )
	self.log.debug "Declaring on_finish callback: %p" % [ block ]
	define_method( :on_finish, &block )
end

.on_start(&block) ⇒ Object

Register a callback that will be called at the start of each new generation. It will be called with the result of the last generation, or nil if this is the 0th (axiom) generation.



53
54
55
56
# File 'lib/l_system/production_adapter.rb', line 53

def self::on_start( &block )
	self.log.debug "Declaring on_start callback: %p" % [ block ]
	define_method( :on_start, &block )
end

.production_map(productions = {}) ⇒ Object

Declare a Hash of symbols to methods that should be called when one appears in a generation.



34
35
36
37
38
39
40
# File 'lib/l_system/production_adapter.rb', line 34

def self::production_map( productions={} )
	unless productions.empty?
		self.production_map = productions
	end

	return @production_map
end

.production_map=(new_map) ⇒ Object

Set the Hash of symbols to methods that should be called when one appears in a generation.



45
46
47
# File 'lib/l_system/production_adapter.rb', line 45

def self::production_map=( new_map )
	@production_map.replace( new_map )
end

.result(&block) ⇒ Object

Register a callback that will be called to obtain the result of running a generation. The result of calling the block will be passed to this generation’s #on_finish callback (if there is one), the next generation’s #on_start callback (if there is one and there’s successive geneation), and returned from #run if this was the last generation.



64
65
66
67
# File 'lib/l_system/production_adapter.rb', line 64

def self::result( &block )
	self.log.debug "Declaring result callback: %p" % [ block ]
	define_method( :result, &block )
end

Instance Method Details

#make_dispatch_tableObject

Return a Hash of symbols to bound Methods to call for their productions from the current #production_map.



140
141
142
143
144
# File 'lib/l_system/production_adapter.rb', line 140

def make_dispatch_table
	return self.class.production_map.each_with_object( {} ) do |(symbol, method_name), hash|
		hash[ symbol ] = self.method( method_name )
	end
end

#run(rules_engine, iterations) ⇒ Object

Run productions for each generation produced by the given rules_engine up to iterations times.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/l_system/production_adapter.rb', line 100

def run( rules_engine, iterations )
	self.log.debug "Running %p for up to %d iterations" % [ rules_engine, iterations ]

	return rules_engine.each.with_index.inject( nil ) do |result, (generation, i)|
		self.log.debug "Running generation %d" % [ i ]
		self.on_start( i, result ) if self.respond_to?( :on_start )
		self.run_generation( generation )
		result = self.result( i ) if self.respond_to?( :result )
		self.log.debug "Result [%d] is: %p" % [ i, result ]
		self.on_finish( i, result ) if self.respond_to?( :on_finish )

		break result if i >= iterations - 1
		result
	end
end

#run_generation(generation) ⇒ Object

Run the specified generation by calling productions for each of its symbols.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/l_system/production_adapter.rb', line 119

def run_generation( generation )

	# Make a new one every time to support self-mutating adapters
	dispatch_table = self.make_dispatch_table

	generation.each_char do |symbol|
		callback = dispatch_table[ symbol ]

		unless callback
			self.log.warn "No production for symbol %p" % [ symbol ]
			next
		end

		self.log.debug "%p -> %p" % [ symbol, callback ]
		callback.call
	end
end