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