lib/test_dummy.rb in test_dummy-0.4.0 vs lib/test_dummy.rb in test_dummy-0.5.0
- old
+ new
@@ -1,9 +1,12 @@
module TestDummy
# == Submodules ============================================================
+ autoload(:Definition, 'test_dummy/definition')
autoload(:Helper, 'test_dummy/helper')
+ autoload(:Loader, 'test_dummy/loader')
+ autoload(:Operation, 'test_dummy/operation')
autoload(:Support, 'test_dummy/support')
autoload(:TestHelper, 'test_dummy/test_helper')
# == Rails Hook ============================================================
@@ -37,52 +40,56 @@
# be specified.
def self.dummy_extensions_path=(value)
@dummy_extensions_path = value
end
+ # This is called when this module is included.
def self.included(base)
base.send(:extend, ClassMethods)
base.send(:include, InstanceMethods)
end
+ # Used to dynamically declare extensions on a particular class. Has the
+ # effect of executing the block in the context of the class given.
def self.declare(on_class, &block)
on_class.instance_eval(&block)
end
# Adds a mixin to the core Helper module
def self.add_module(new_module)
Helper.send(:extend, new_module)
end
- # Used to configure defaults or aliases that can be used by all definitions.
+ # Used to configure defaults or aliases that can be used by all operations.
# Takes a block that should call definition methods like `dummy`.
def self.define(&block)
instance_eval(&block)
end
# Used in an initializer to define things that can be dummied by all
# models if these properties are available.
- def self.dummy(*names, &block)
- case (names.last)
+ def self.dummy(*fields, &block)
+ case (fields.last)
when Hash
- options = names.pop
+ options = fields.pop
end
-
+
+ # REFACTOR: Adapt to new Operation style
if (options and options[:with])
with = options[:with]
- names.each do |name|
+ fields.each do |name|
if (Helper.respond_to?(with))
Helper.send(:alias_method, name, with)
else
Helper.send(:define_method, name) do
send(with)
end
end
end
else
- names.each do |name|
+ fields.each do |name|
Helper.send(:define_method, name, &block)
end
end
end
@@ -92,363 +99,105 @@
end
module ClassMethods
# Returns a Hash which describes the dummy configuration for this
# Model class.
- def dummy_attributes
- @test_dummy ||= { }
+ def dummy_definition
+ @dummy_definition ||= TestDummy::Definition.new
+
+ TestDummy::Loader.load!(self)
+
+ @dummy_definition
end
# Declares how to fake one or more attributes. Accepts a block
# that can receive up to two parameters, the first the instance of
# the model being created, the second the parameters supplied to create
# it. The first and second parameters may be nil.
- def dummy(*names, &block)
- options = nil
-
- case (names.last)
- when Hash
- options = names.pop
- end
-
- @test_dummy ||= { }
- @test_dummy_order ||= [ ]
- @test_dummy_tags ||= { }
-
- names.flatten.each do |name|
- name = name.to_sym
- from = nil
- create_options_proc = nil
-
- if (options)
- if (options[:only])
- tags = [ options[:only] ].flatten.compact
-
- if (tags.any?)
- set = @test_dummy_tags[name] ||= { }
-
- set[:only] = tags
- end
- end
-
- if (options[:except])
- tags = [ options[:except] ].flatten.compact
-
- if (tags.any?)
- set = @test_dummy_tags[name] ||= { }
-
- set[:except] = tags
- end
- end
-
- if (options[:with])
- if (block)
- raise TestDummy::Exception, "Cannot use block and :with option at the same time."
- end
-
- block =
- case (with = options[:with])
- when Proc
- with
- when String, Symbol
- lambda { send(with) }
- else
- lambda { with }
- end
- end
-
- # The :inherit directive is used to pass arguments through to the
- # create_dummy call on the association's class.
- if (inherit = options[:inherit])
- inherit_options = Hash[
- inherit.collect do |attribute, spec|
- [
- attribute.to_sym,
- case (spec)
- when Array
- spec.collect(&:to_sym)
- when String
- spec.split('.').collect(&:to_sym)
- when Proc
- spec
- end
- ]
- end
- ]
-
- create_options_proc = lambda do |target, model, with_attributes|
- inherit_options.each do |attribute, spec|
- target[attribute] ||=
- case (spec)
- when Array
- spec.inject(model) do |_model, _method|
- _model ? _model.send(_method) : nil
- end
- when Proc
- proc.call(model, with_attributes)
- end
- end
- end
- end
-
- if (from = options[:from])
- if (block)
- raise TestDummy::Exception, "Cannot use block, :with, or :from option at the same time."
- end
-
- case (from)
- when Array
- # Already in correct form
- when Hash
- from = from.to_a
- when String
- from = from.split('.')
- else
- raise TestDummy::Exception, "Argument to :from must be a String, Array or Hash."
- end
- end
-
- reflection_class, foreign_key = TestDummy::Support.reflection_properties(self, name)
-
- if (reflection_class and foreign_key)
- block = lambda do |model, with_attributes|
- unless ((with_attributes and (with_attributes.key?(name) or with_attributes.key?(foreign_key))) or model.send(name).present?)
- object = from && from.inject(model) do |_model, _method|
- _model ? _model.send(_method) : nil
- end
-
- object ||=
- reflection_class.create_dummy(with_attributes) do |target|
- if (create_options_proc)
- create_options_proc.call(target, model, with_attributes)
- end
- end
-
- model.send(:"#{name}=", object)
- end
- end
- end
+ def dummy(*fields)
+ options =
+ case (fields.last)
+ when Hash
+ fields.pop
+ else
+ { }
end
- # For associations, delay creation of block until first call
- # to allow for additional relationships to be defined after
- # the to_dummy call. Leave placeholder (true) instead.
-
- @test_dummy[name] = block || true
- @test_dummy_order << name
+ if (block_given?)
+ options = options.merge(:block => Proc.new)
end
+
+ self.dummy_definition.define_operation(self, fields, options)
end
- # Returns true if all the supplied attribute names have defined
+ # Returns true if all the supplied attribute fields have defined
# dummy methods, or false otherwise.
- def can_dummy?(*names)
- @test_dummy ||= { }
-
- names.flatten.reject do |name|
- @test_dummy.key?(name)
- end.empty?
+ def can_dummy?(*fields)
+ @test_dummy and @test_dummy.can_dummy?(*fields) or false
end
# Builds a dummy model with some parameters set as supplied. The
# new model is provided to the optional block for manipulation before
# the dummy operation is completed. Returns a dummy model which has not
# been saved.
- def build_dummy(with_attributes = nil, tags = nil)
- load_dummy_declaration!
-
- build_scope = (method(:scoped).arity == 1) ? scoped(nil).scope(:create) : scoped.scope_for_create
+ def build_dummy(create_attributes = nil, tags = nil)
+ build_scope = where(nil)
- model = new(TestDummy::Support.combine_attributes(build_scope, with_attributes))
+ create_attributes = TestDummy::Support.combine_attributes(build_scope, create_attributes)
+ model = new(create_attributes)
+
yield(model) if (block_given?)
- self.execute_dummy_operation(model, with_attributes, tags)
-
+ self.dummy_definition.apply!(model, create_attributes, tags)
+
model
end
# Builds a dummy model with some parameters set as supplied. The
# new model is provided to the optional block for manipulation before
# the dummy operation is completed and the model is saved. Returns a
# dummy model. The model may not have been saved if there was a
# validation failure, or if it was blocked by a callback.
- def create_dummy(*args, &block)
- if (args.last.is_a?(Hash))
- with_attributes = args.pop
+ def create_dummy(*tags, &block)
+ if (tags.last.is_a?(Hash))
+ create_attributes = tags.pop
end
- model = build_dummy(with_attributes, args, &block)
-
+ model = build_dummy(create_attributes, tags, &block)
+
model.save
+
+ self.dummy_definition.apply_after_save!(model, create_attributes, tags)
model
end
# Builds a dummy model with some parameters set as supplied. The
# new model is provided to the optional block for manipulation before
# the dummy operation is completed and the model is saved. Returns a
# dummy model. Will throw ActiveRecord::RecordInvalid if there was al20
# validation failure, or ActiveRecord::RecordNotSaved if the save was
# blocked by a callback.
- def create_dummy!(*args, &block)
- if (args.last.is_a?(Hash))
- with_attributes = args.pop
+ def create_dummy!(*tags, &block)
+ if (tags.last.is_a?(Hash))
+ create_attributes = tags.pop
end
- model = build_dummy(with_attributes, args, &block)
+ model = build_dummy(create_attributes, tags, &block)
model.save!
- model
- end
-
- # Produces dummy data for a single attribute.
- def dummy_attribute(name, with_attributes = nil)
- with_attributes = TestDummy.combine_attributes(scoped.scope_for_create, with_attributes)
-
- dummy_method_call(nil, with_attributes, dummy_method(name))
- end
-
- # Produces a complete set of dummy attributes. These can be used to
- # create a model.
- def dummy_attributes(with_attributes = nil, tags = nil)
- with_attributes = TestDummy.combine_attributes(scoped.scope_for_create, with_attributes)
-
- @test_dummy_order.each do |field|
- next if (with_attributes.key?(field))
+ self.dummy_definition.apply_after_save!(model, create_attributes, tags)
- if (when_tagged = @test_dummy_when[field])
- next if (!tags or (tags & when_tagged).empty?)
- end
-
- result = dummy(field, with_attributes)
-
- case (result)
- when nil, with_attributes
- # Declined to populate parameters if method returns nil
- # or returns the existing parameter set.
- else
- with_attributes[field] = result
- end
- end
-
- with_attributes
- end
-
- # This performs the dummy operation on a model with an optional set
- # of parameters.
- def execute_dummy_operation(model, with_attributes = nil, tags = nil)
- load_dummy_declaration!
-
- return model unless (@test_dummy_order)
-
- @test_dummy_order.each do |name|
- if (tag_conditions = @test_dummy_tags[name])
- if (required_tags = tag_conditions[:only])
- next if (!tags or (tags & required_tags).empty?)
- end
-
- if (excluding_tags = tag_conditions[:except])
- next if (tags and (tags & excluding_tags).any?)
- end
- end
-
- if (respond_to?(:reflect_on_association) and reflection = reflect_on_association(name))
- foreign_key = (reflection.respond_to?(:foreign_key) ? reflection.foreign_key : reflection.primary_key_name).to_sym
-
- unless ((with_attributes and (with_attributes.key?(name.to_sym) or with_attributes.key?(foreign_key.to_sym))) or model.send(name).present?)
- model.send(:"#{name}=", dummy_method_call(model, with_attributes, dummy_method(name)))
- end
- elsif (respond_to?(:association_reflection) and reflection = association_reflection(name))
- key = reflection[:key] || :"#{name.to_s.underscore}_id"
-
- unless ((with_attributes and (with_attributes.key?(name.to_sym) or with_attributes.key?(key.to_sym))) or model.send(name).present?)
- model.send(:"#{name}=", dummy_method_call(model, with_attributes, dummy_method(name)))
- end
- else
- unless (with_attributes and (with_attributes.key?(name.to_sym) or with_attributes.key?(name.to_s)))
- model.send(:"#{name}=", dummy_method_call(model, with_attributes, dummy_method(name)))
- end
- end
- end
-
model
end
-
- protected
- def load_dummy_declaration!
- return unless (@_dummy_module.nil?)
-
- @_dummy_module =
- begin
- dummy_path = File.expand_path(
- "#{name.underscore}.rb",
- TestDummy.dummy_extensions_path
- )
-
- if (File.exist?(dummy_path))
- load(dummy_path)
- end
- rescue LoadError
- # Persist that this load attempt failed and don't retry later.
- false
- end
- end
-
- def dummy_method_call(model, with_attributes, block)
- case (block.arity)
- when 2
- block.call(model, with_attributes)
- when 1
- block.call(model)
- else
- model.instance_eval(&block)
- end
- end
-
- def dummy_method(name)
- name = name.to_sym
-
- block = @test_dummy[name]
-
- case (block)
- when Module
- block.method(name)
- when Symbol
- Helper.method(name)
- when true
- # Configure association dummy the first time it is called
- if (respond_to?(:reflect_on_association) and reflection = reflect_on_association(name))
- foreign_key = (reflection.respond_to?(:foreign_key) ? reflection.foreign_key : reflection.primary_key_name).to_sym
-
- @test_dummy[name] =
- lambda do |model, with_attributes|
- (with_attributes and (with_attributes.key?(foreign_key) or with_attributes.key?(name))) ? nil : reflection.klass.send(:create_dummy)
- end
- elsif (respond_to?(:association_reflection) and reflection = association_reflection(name))
- key = reflection[:key] || :"#{name.to_s.underscore}_id"
-
- @test_dummy[name] =
- lambda do |model, with_attributes|
- (with_attributes and (with_attributes.key?(key) or with_attributes.key?(name))) ? nil : reflection[:associated_class].send(:create_dummy)
- end
- elsif (TestDummy::Helper.respond_to?(name))
- @test_dummy[name] = lambda do |model, with_attributes|
- TestDummy::Helper.send(name)
- end
- else
- raise "Cannot dummy unknown relationship #{name}"
- end
- else
- block
- end
- end
end
module InstanceMethods
# Assigns any attributes which can be dummied that have not already
# been populated.
- def dummy!(with_attributes = nil)
- self.class.execute_dummy_operation(self, with_attributes)
+ def dummy!(create_attributes = nil, tags = nil)
+ self.class.dummy_definition.apply!(self, create_attributes, tags)
end
end
end