Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

big attribute sequence cleanup

  • Loading branch information...
commit c2251954ea2408f94a19907e1a56ab70aba98c55 1 parent 8323b09
Francis Hwang authored
304 lib/sample_models/attribute_sequence.rb
... ... @@ -1,187 +1,167 @@
1 1 module SampleModels
2   - class AttributeSequence
3   - def self.build(*args)
4   - Builder.new(*args).run
5   - end
6   -
7   - def initialize(model, column, validation, input)
8   - @model, @column, @validation, @input = model, column, validation, input
9   - @number = 0
  2 + module AttributeSequence
  3 + def self.build(pass, model, column, force_unique, force_email_format)
  4 + sequence = nil
  5 + validations = model.validations(column.name)
  6 + belongs_to_assocs = model.belongs_to_associations
  7 + if force_email_format
  8 + sequence = EmailSource.new
  9 + elsif assoc = belongs_to_assocs.detect { |a| a.foreign_key == column.name }
  10 + if validations.any?(&:presence?)
  11 + sequence = RequiredBelongsToSource.new(assoc)
  12 + elsif pass == :first
  13 + sequence = FirstPassBelongsToSource.new
  14 + else
  15 + sequence = SecondPassBelongsToSource.new(model, assoc)
  16 + end
  17 + elsif validations.any?(&:email_format?)
  18 + sequence = EmailSource.new
  19 + elsif v = validations.detect(&:inclusion?)
  20 + sequence = InclusionSource.new(v)
  21 + else
  22 + sequence = SimpleSource.new(column)
  23 + end
  24 + if (v = validations.detect(&:uniqueness?)) || force_unique
  25 + v ||= Model::Validation.new(:validates_uniqueness_of)
  26 + sequence = UniquenessFilter.new(model, column, v, sequence)
  27 + end
  28 + sequence
  29 + end
  30 +
  31 + class AbstractSource
  32 + def initialize
  33 + @number = 0
  34 + end
  35 +
  36 + def next
  37 + @number += 1
  38 + value
  39 + end
10 40 end
11   -
12   - def belongs_to_association
13   - @model.belongs_to_associations.detect { |a|
14   - a.foreign_key == @column.name
15   - }
  41 +
  42 + class EmailSource < AbstractSource
  43 + def value
  44 + "john.doe.#{@number}@example.com"
  45 + end
16 46 end
17   -
18   - def next
19   - @number += 1
20   - @input.next if @input
21   - value
  47 +
  48 + class FirstPassBelongsToSource < AbstractSource
  49 + def value
  50 + nil
  51 + end
22 52 end
23   -
24   - def value
25   - case @column.type
26   - when :string, :text
27   - "#{@column.name} #{@number}"
28   - when :integer
29   - belongs_to_association ? belongs_to_assoc_foreign_key_value : @number
30   - when :datetime
31   - Time.now.utc - @number.minutes
32   - when :date
33   - Date.today - @number
34   - when :float
35   - @number.to_f
36   - end
  53 +
  54 + class InclusionSource < AbstractSource
  55 + def initialize(validation)
  56 + super()
  57 + @validation = validation
  58 + end
  59 +
  60 + def value
  61 + @validation.config[:in].first
  62 + end
37 63 end
38   -
39   - class Builder
40   - def initialize(pass, model, column, force_unique, force_email_format)
41   - @pass, @model, @column, @force_unique, @force_email_format =
42   - pass, model, column, force_unique, force_email_format
  64 +
  65 + class RequiredBelongsToSource < AbstractSource
  66 + def initialize(assoc)
  67 + super()
  68 + @assoc = assoc
  69 + @previous_instances = {}
43 70 end
44   -
45   - def base
46   - base_class = SampleModels.const_get(
47   - "#{@pass.to_s.capitalize}PassBaseAttributeSequence"
48   - )
49   - base_class.new(@model, @column)
50   - end
51   -
52   - def run
53   - input = base
54   - if @force_email_format
55   - input = ValidatesEmailFormatOfAttributeSequence.new(
56   - @model, @column, nil, input
  71 +
  72 + def existing_instance_not_previously_returned
  73 + previous_ids = @previous_instances.values.map(&:id)
  74 + instance = nil
  75 + if previous_ids.empty?
  76 + @assoc.klass.last
  77 + else
  78 + @assoc.klass.last(
  79 + :conditions => ["id not in (?)", previous_ids]
57 80 )
58 81 end
59   - uniqueness_validation = if @force_unique
60   - Model::Validation.new(:validates_uniqueness_of)
61   - end
62   - @model.validations(@column.name).each do |validation|
63   - if validation.type == :validates_uniqueness_of
64   - uniqueness_validation = validation
65   - elsif s_class = sequence_class(validation)
66   - input = s_class.new(@model, @column, validation, input)
67   - end
68   - end
69   - if uniqueness_validation
70   - input = ValidatesUniquenessOfAttributeSequence.new(
71   - @model, @column, uniqueness_validation, input
72   - )
73   - end
74   - input
75 82 end
76   -
77   - def sequence_class(validation)
78   - sequence_name = validation.type.to_s.camelize + 'AttributeSequence'
79   - if SampleModels.const_defined?(sequence_name)
80   - SampleModels.const_get(sequence_name)
  83 +
  84 + def set_instance
  85 + instance = existing_instance_not_previously_returned
  86 + instance ||= @assoc.klass.sample
  87 + @previous_instances[@number] = instance
  88 + end
  89 +
  90 + def value
  91 + if @previous_instances[@number]
  92 + value = @previous_instances[@number]
  93 + begin
  94 + value.reload
  95 + value.id
  96 + rescue ActiveRecord::RecordNotFound
  97 + set_instance
  98 + @previous_instances[@number].id
  99 + end
  100 + else
  101 + set_instance
  102 + @previous_instances[@number].id
81 103 end
82 104 end
83 105 end
84   - end
85   -
86   - class FirstPassBaseAttributeSequence < AttributeSequence
87   - def initialize(model, column)
88   - super(model, column, nil, nil)
89   - end
90   -
91   - def belongs_to_assoc_foreign_key_value
92   - nil
93   - end
94   - end
95   -
96   - class SecondPassBaseAttributeSequence < AttributeSequence
97   - def initialize(model, column)
98   - super(model, column, nil, nil)
99   - @previous_values = {}
100   - end
101   -
102   - def belongs_assoc_value_already_used?(record)
103   - @previous_values.any? { |prev_num, prev_record|
104   - prev_record == record && prev_num != @number
105   - }
106   - end
107   -
108   - def belongs_to_assoc_foreign_key_value
109   - assoc_klass = belongs_to_association.klass
110   - unless assoc_klass == @model.ar_class
111   - record = (assoc_klass.last || assoc_klass.sample)
112   - while belongs_assoc_value_already_used?(record)
113   - record = assoc_klass.sample
  106 +
  107 + class SecondPassBelongsToSource < AbstractSource
  108 + def initialize(model, assoc)
  109 + super()
  110 + @model, @assoc = model, assoc
  111 + end
  112 +
  113 + def value
  114 + assoc_klass = @assoc.klass
  115 + unless assoc_klass == @model.ar_class
  116 + record = (assoc_klass.last || assoc_klass.sample)
  117 + record.id
114 118 end
115   - @previous_values[@number] = record
116   - record.id
117 119 end
118 120 end
119   - end
120   -
121   - class ValidatesEmailFormatOfAttributeSequence < AttributeSequence
122   - def value
123   - "john.doe.#{@number}@example.com"
124   - end
125   - end
126   -
127   - class ValidatesInclusionOfAttributeSequence < AttributeSequence
128   - def value
129   - @validation.config[:in].first
130   - end
131   - end
132   -
133   - class ValidatesPresenceOfAttributeSequence < AttributeSequence
134   - def belongs_to_value
135   - @previous_belongs_to_instances ||= {}
136   - if @previous_belongs_to_instances[@number]
137   - value = @previous_belongs_to_instances[@number]
138   - begin
139   - value.reload
140   - value.id
141   - rescue ActiveRecord::RecordNotFound
142   - set_belongs_to_instance
143   - @previous_belongs_to_instances[@number].id
  121 +
  122 + class SimpleSource < AbstractSource
  123 + def initialize(column)
  124 + super()
  125 + @column = column
  126 + end
  127 +
  128 + def value
  129 + case @column.type
  130 + when :string, :text
  131 + "#{@column.name} #{@number}"
  132 + when :integer
  133 + @number
  134 + when :datetime
  135 + Time.now.utc - @number.minutes
  136 + when :date
  137 + Date.today - @number
  138 + when :float
  139 + @number.to_f
144 140 end
145   - else
146   - set_belongs_to_instance
147   - @previous_belongs_to_instances[@number].id
148 141 end
149 142 end
150   -
151   - def existing_instance_not_previously_returned
152   - previous_ids = @previous_belongs_to_instances.values.map(&:id)
153   - instance = nil
154   - if previous_ids.empty?
155   - belongs_to_association.klass.last
156   - else
157   - belongs_to_association.klass.last(
158   - :conditions => ["id not in (?)", previous_ids]
159   - )
  143 +
  144 + class UniquenessFilter
  145 + def initialize(model, column, validation, input)
  146 + @model, @column, @validation, @input =
  147 + model, column, validation, input
160 148 end
161   - end
162   -
163   - def set_belongs_to_instance
164   - instance = existing_instance_not_previously_returned
165   - instance ||= belongs_to_association.klass.sample
166   - @previous_belongs_to_instances[@number] = instance
167   - end
168   -
169   - def value
170   - belongs_to_association ? belongs_to_value : super
171   - end
172   - end
173   -
174   - class ValidatesUniquenessOfAttributeSequence < AttributeSequence
175   - def value
176   - v = @input.value
177   - unless @validation.config[:allow_nil] && v.nil?
178   - unless @validation.config[:allow_blank] && v.blank?
179   - until @model.unique?(@column.name, v)
180   - v = @input.next
  149 +
  150 + def next
  151 + v = @input.next
  152 + unless @validation.config[:allow_nil] && v.nil?
  153 + unless @validation.config[:allow_blank] && v.blank?
  154 + until @model.unique?(@column.name, v)
  155 + v = @input.next
  156 + end
181 157 end
182 158 end
  159 + v
  160 + end
  161 +
  162 + def value
  163 + self.next
183 164 end
184   - v
185 165 end
186 166 end
187 167 end
4 lib/sample_models/model.rb
@@ -100,6 +100,10 @@ def inclusion?
100 100 def presence?
101 101 @type == :validates_presence_of
102 102 end
  103 +
  104 + def uniqueness?
  105 + @type == :validates_uniqueness_of
  106 + end
103 107 end
104 108 end
105 109 end
2  test/unit/belongs_to_test.rb
... ... @@ -1,4 +1,4 @@
1   -require File.dirname(__FILE__) + "/../test_helper"
  1 +require File.expand_path(File.join(File.dirname(__FILE__), '/../test_helper'))
2 2
3 3 class BelongsToTest < SampleModelsTestCase
4 4 def test_associated_with_belongs_to_recipient_by_default

0 comments on commit c225195

Please sign in to comment.
Something went wrong with that request. Please try again.