Class: FluentFixtures::Factory

Inherits:
Object
  • Object
show all
Extended by:
Loggability
Includes:
Enumerable
Defined in:
lib/fluent_fixtures/factory.rb

Overview

The fluent fixture monadic factory class.

Constant Summary collapse

CREATE_METHODS =

The methods to look for to save new instances when #create is called

%i[ save_changes save ]
DEFAULT_GENERATOR_LIMIT =

The default limit for generators

10_000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fixture_module, *args, &block) ⇒ Factory

Create a new FluentFactory that will act as a monadic factory for the specified fixture_module, and use the given args in the construction of new objects.



27
28
29
30
31
32
# File 'lib/fluent_fixtures/factory.rb', line 27

def initialize( fixture_module, *args, &block )
	@fixture_module = fixture_module
	@constructor_args = args
	@constructor_block = block
	@decorators = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, &block) ⇒ Object (protected)

Proxy method – look up the decorator with the same name as the method being called, and if one is found, returned a new instance of the factory with the additional decorator.



280
281
282
# File 'lib/fluent_fixtures/factory.rb', line 280

def method_missing( sym, *args, &block )
	return self.mutate( sym, *args, &block )
end

Instance Attribute Details

#constructor_argsObject (readonly)

The Array of arguments to pass to the constructor when creating a new fixtured object.



51
52
53
# File 'lib/fluent_fixtures/factory.rb', line 51

def constructor_args
  @constructor_args
end

#constructor_blockObject (readonly)

The block to pass to the constructor when creating a new fixtured object.



55
56
57
# File 'lib/fluent_fixtures/factory.rb', line 55

def constructor_block
  @constructor_block
end

#decoratorsObject (readonly)

The decorators that will be applied to the fixtured object when it’s created.



47
48
49
# File 'lib/fluent_fixtures/factory.rb', line 47

def decorators
  @decorators
end

#fixture_moduleObject (readonly)

The fixture module that contains the decorator declarations



43
44
45
# File 'lib/fluent_fixtures/factory.rb', line 43

def fixture_module
  @fixture_module
end

Instance Method Details

#create(args = {}, &block) ⇒ Object

Return a saved #instance of the fixtured object.



105
106
107
108
109
110
111
112
113
# File 'lib/fluent_fixtures/factory.rb', line 105

def create( args={}, &block )
	obj = self.with_transaction do
		obj = self.instance( args, &block )
		obj = self.try_to_save( obj )
		obj
	end

	return obj
end

#decorated_with(&block) ⇒ Object

Return a copy of the factory that will apply the specified block as a decorator.



117
118
119
# File 'lib/fluent_fixtures/factory.rb', line 117

def decorated_with( &block )
	return self.mutate( nil, &block )
end

#each(&block) ⇒ Object

Iterate over DEFAULT_GENERATOR_LIMIT instances of the fixtured object, yielding each new instance if a block is provided. If no block is provided, returns an Enumerator.



125
126
127
128
# File 'lib/fluent_fixtures/factory.rb', line 125

def each( &block )
	return self.generator unless block
	return self.generator.each( &block )
end

#generator(create: false, limit: DEFAULT_GENERATOR_LIMIT, &block) ⇒ Object

Return an infinite generator for unsaved instances of the fixtured object.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/fluent_fixtures/factory.rb', line 132

def generator( create: false, limit: DEFAULT_GENERATOR_LIMIT, &block )
	return Enumerator.new( limit || Float::INFINITY ) do |yielder|
		count = 0
		constructor = create ? :create : :instance
		loop do
			break if limit && count >= limit

			obj = if block
					self.send( constructor, &block.curry(2)[count] )
				else
					self.send( constructor )
				end

			yielder.yield( obj )

			count += 1
		end
	end
end

#initialize_copy(original) ⇒ Object

Copy constructor – make a distinct copy of the clone’s decorators.



36
37
38
# File 'lib/fluent_fixtures/factory.rb', line 36

def initialize_copy( original )
	@decorators = @decorators.dup
end

#inspectObject

Return a human-readable representation of the object suitable for debugging.



154
155
156
157
158
159
160
161
162
163
# File 'lib/fluent_fixtures/factory.rb', line 154

def inspect
	decorator_description = self.decorators.map( &:first ).join( ' + ' )

	return "#<%p:%0#16x for %p%s>" % [
		self.class,
		self.__id__ * 2,
		self.fixture_module,
		decorator_description.empty? ? '' : ' + ' + decorator_description
	]
end

#instance(args = {}, &block) ⇒ Object

Create an instance, apply declared decorators in order, and return the resulting object.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/fluent_fixtures/factory.rb', line 69

def instance( args={}, &block )
	instance = self.fixture_module.
		fixtured_instance( *self.constructor_args, &self.constructor_block )

	self.decorators.each do |decorator_name, decorator_args, block|
		# :TODO: Reify other fixtures in `decorator_args` here?
		if !decorator_name
			self.apply_inline_decorator( instance, block )
		elsif self.fixture_module.decorators.key?( decorator_name )
			instance = self.apply_named_decorator( instance, decorator_args, decorator_name )
		else
			self.apply_method_decorator( instance, decorator_args, decorator_name, block )
		end
	end

	args.each_pair do |attrname, value|
		# :TODO: Reify the `value` if it responds to #create?
		instance.public_send( "#{attrname}=", value )
	end

	# If the factory was called with a block, use it as a final decorator before
	# returning it.
	if block
		self.log.debug "Applying inline decorator %p" % [ block ]
		if block.arity.zero?
			instance.instance_exec( &block )
		else
			block.call( instance )
		end
	end

	return instance
end

#mutate(name, *args, &block) ⇒ Object

Return a new clone of the receiver with an additional decorator composed of the specified name, args, and block.



60
61
62
63
64
# File 'lib/fluent_fixtures/factory.rb', line 60

def mutate( name, *args, &block )
	new_instance = self.dup
	new_instance.decorators << [ name, args, block ]
	return new_instance
end