Browse files

big attribute sequence cleanup

  • Loading branch information...
1 parent 8323b09 commit c2251954ea2408f94a19907e1a56ab70aba98c55 @fhwang committed Mar 4, 2012
Showing with 147 additions and 163 deletions.
  1. +142 −162 lib/sample_models/attribute_sequence.rb
  2. +4 −0 lib/sample_models/model.rb
  3. +1 −1 test/unit/belongs_to_test.rb
View
304 lib/sample_models/attribute_sequence.rb
@@ -1,187 +1,167 @@
module SampleModels
- class AttributeSequence
- def self.build(*args)
- Builder.new(*args).run
- end
-
- def initialize(model, column, validation, input)
- @model, @column, @validation, @input = model, column, validation, input
- @number = 0
+ module AttributeSequence
+ def self.build(pass, model, column, force_unique, force_email_format)
+ sequence = nil
+ validations = model.validations(column.name)
+ belongs_to_assocs = model.belongs_to_associations
+ if force_email_format
+ sequence = EmailSource.new
+ elsif assoc = belongs_to_assocs.detect { |a| a.foreign_key == column.name }
+ if validations.any?(&:presence?)
+ sequence = RequiredBelongsToSource.new(assoc)
+ elsif pass == :first
+ sequence = FirstPassBelongsToSource.new
+ else
+ sequence = SecondPassBelongsToSource.new(model, assoc)
+ end
+ elsif validations.any?(&:email_format?)
+ sequence = EmailSource.new
+ elsif v = validations.detect(&:inclusion?)
+ sequence = InclusionSource.new(v)
+ else
+ sequence = SimpleSource.new(column)
+ end
+ if (v = validations.detect(&:uniqueness?)) || force_unique
+ v ||= Model::Validation.new(:validates_uniqueness_of)
+ sequence = UniquenessFilter.new(model, column, v, sequence)
+ end
+ sequence
+ end
+
+ class AbstractSource
+ def initialize
+ @number = 0
+ end
+
+ def next
+ @number += 1
+ value
+ end
end
-
- def belongs_to_association
- @model.belongs_to_associations.detect { |a|
- a.foreign_key == @column.name
- }
+
+ class EmailSource < AbstractSource
+ def value
+ "john.doe.#{@number}@example.com"
+ end
end
-
- def next
- @number += 1
- @input.next if @input
- value
+
+ class FirstPassBelongsToSource < AbstractSource
+ def value
+ nil
+ end
end
-
- def value
- case @column.type
- when :string, :text
- "#{@column.name} #{@number}"
- when :integer
- belongs_to_association ? belongs_to_assoc_foreign_key_value : @number
- when :datetime
- Time.now.utc - @number.minutes
- when :date
- Date.today - @number
- when :float
- @number.to_f
- end
+
+ class InclusionSource < AbstractSource
+ def initialize(validation)
+ super()
+ @validation = validation
+ end
+
+ def value
+ @validation.config[:in].first
+ end
end
-
- class Builder
- def initialize(pass, model, column, force_unique, force_email_format)
- @pass, @model, @column, @force_unique, @force_email_format =
- pass, model, column, force_unique, force_email_format
+
+ class RequiredBelongsToSource < AbstractSource
+ def initialize(assoc)
+ super()
+ @assoc = assoc
+ @previous_instances = {}
end
-
- def base
- base_class = SampleModels.const_get(
- "#{@pass.to_s.capitalize}PassBaseAttributeSequence"
- )
- base_class.new(@model, @column)
- end
-
- def run
- input = base
- if @force_email_format
- input = ValidatesEmailFormatOfAttributeSequence.new(
- @model, @column, nil, input
+
+ def existing_instance_not_previously_returned
+ previous_ids = @previous_instances.values.map(&:id)
+ instance = nil
+ if previous_ids.empty?
+ @assoc.klass.last
+ else
+ @assoc.klass.last(
+ :conditions => ["id not in (?)", previous_ids]
)
end
- uniqueness_validation = if @force_unique
- Model::Validation.new(:validates_uniqueness_of)
- end
- @model.validations(@column.name).each do |validation|
- if validation.type == :validates_uniqueness_of
- uniqueness_validation = validation
- elsif s_class = sequence_class(validation)
- input = s_class.new(@model, @column, validation, input)
- end
- end
- if uniqueness_validation
- input = ValidatesUniquenessOfAttributeSequence.new(
- @model, @column, uniqueness_validation, input
- )
- end
- input
end
-
- def sequence_class(validation)
- sequence_name = validation.type.to_s.camelize + 'AttributeSequence'
- if SampleModels.const_defined?(sequence_name)
- SampleModels.const_get(sequence_name)
+
+ def set_instance
+ instance = existing_instance_not_previously_returned
+ instance ||= @assoc.klass.sample
+ @previous_instances[@number] = instance
+ end
+
+ def value
+ if @previous_instances[@number]
+ value = @previous_instances[@number]
+ begin
+ value.reload
+ value.id
+ rescue ActiveRecord::RecordNotFound
+ set_instance
+ @previous_instances[@number].id
+ end
+ else
+ set_instance
+ @previous_instances[@number].id
end
end
end
- end
-
- class FirstPassBaseAttributeSequence < AttributeSequence
- def initialize(model, column)
- super(model, column, nil, nil)
- end
-
- def belongs_to_assoc_foreign_key_value
- nil
- end
- end
-
- class SecondPassBaseAttributeSequence < AttributeSequence
- def initialize(model, column)
- super(model, column, nil, nil)
- @previous_values = {}
- end
-
- def belongs_assoc_value_already_used?(record)
- @previous_values.any? { |prev_num, prev_record|
- prev_record == record && prev_num != @number
- }
- end
-
- def belongs_to_assoc_foreign_key_value
- assoc_klass = belongs_to_association.klass
- unless assoc_klass == @model.ar_class
- record = (assoc_klass.last || assoc_klass.sample)
- while belongs_assoc_value_already_used?(record)
- record = assoc_klass.sample
+
+ class SecondPassBelongsToSource < AbstractSource
+ def initialize(model, assoc)
+ super()
+ @model, @assoc = model, assoc
+ end
+
+ def value
+ assoc_klass = @assoc.klass
+ unless assoc_klass == @model.ar_class
+ record = (assoc_klass.last || assoc_klass.sample)
+ record.id
end
- @previous_values[@number] = record
- record.id
end
end
- end
-
- class ValidatesEmailFormatOfAttributeSequence < AttributeSequence
- def value
- "john.doe.#{@number}@example.com"
- end
- end
-
- class ValidatesInclusionOfAttributeSequence < AttributeSequence
- def value
- @validation.config[:in].first
- end
- end
-
- class ValidatesPresenceOfAttributeSequence < AttributeSequence
- def belongs_to_value
- @previous_belongs_to_instances ||= {}
- if @previous_belongs_to_instances[@number]
- value = @previous_belongs_to_instances[@number]
- begin
- value.reload
- value.id
- rescue ActiveRecord::RecordNotFound
- set_belongs_to_instance
- @previous_belongs_to_instances[@number].id
+
+ class SimpleSource < AbstractSource
+ def initialize(column)
+ super()
+ @column = column
+ end
+
+ def value
+ case @column.type
+ when :string, :text
+ "#{@column.name} #{@number}"
+ when :integer
+ @number
+ when :datetime
+ Time.now.utc - @number.minutes
+ when :date
+ Date.today - @number
+ when :float
+ @number.to_f
end
- else
- set_belongs_to_instance
- @previous_belongs_to_instances[@number].id
end
end
-
- def existing_instance_not_previously_returned
- previous_ids = @previous_belongs_to_instances.values.map(&:id)
- instance = nil
- if previous_ids.empty?
- belongs_to_association.klass.last
- else
- belongs_to_association.klass.last(
- :conditions => ["id not in (?)", previous_ids]
- )
+
+ class UniquenessFilter
+ def initialize(model, column, validation, input)
+ @model, @column, @validation, @input =
+ model, column, validation, input
end
- end
-
- def set_belongs_to_instance
- instance = existing_instance_not_previously_returned
- instance ||= belongs_to_association.klass.sample
- @previous_belongs_to_instances[@number] = instance
- end
-
- def value
- belongs_to_association ? belongs_to_value : super
- end
- end
-
- class ValidatesUniquenessOfAttributeSequence < AttributeSequence
- def value
- v = @input.value
- unless @validation.config[:allow_nil] && v.nil?
- unless @validation.config[:allow_blank] && v.blank?
- until @model.unique?(@column.name, v)
- v = @input.next
+
+ def next
+ v = @input.next
+ unless @validation.config[:allow_nil] && v.nil?
+ unless @validation.config[:allow_blank] && v.blank?
+ until @model.unique?(@column.name, v)
+ v = @input.next
+ end
end
end
+ v
+ end
+
+ def value
+ self.next
end
- v
end
end
end
View
4 lib/sample_models/model.rb
@@ -100,6 +100,10 @@ def inclusion?
def presence?
@type == :validates_presence_of
end
+
+ def uniqueness?
+ @type == :validates_uniqueness_of
+ end
end
end
end
View
2 test/unit/belongs_to_test.rb
@@ -1,4 +1,4 @@
-require File.dirname(__FILE__) + "/../test_helper"
+require File.expand_path(File.join(File.dirname(__FILE__), '/../test_helper'))
class BelongsToTest < SampleModelsTestCase
def test_associated_with_belongs_to_recipient_by_default

0 comments on commit c225195

Please sign in to comment.