class FixtureFarm::FixtureRecorder
Constants
- STORE_PATH
Public Class Methods
new(fixture_name_prefix, new_models = [])
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 7 def initialize(fixture_name_prefix, new_models = []) @fixture_name_prefix = fixture_name_prefix @new_models = new_models @initial_now = Time.zone.now end
recording_session_in_progress?()
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 36 def self.recording_session_in_progress? File.exist?(STORE_PATH) end
resume_recording_session()
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 13 def self.resume_recording_session start_recording_session! unless recording_session_in_progress? recording_session = JSON.load_file(STORE_PATH) new_models = recording_session['new_models'].map do |(class_name, id)| class_name.constantize.find(id) end new(recording_session['fixture_name_prefix'], new_models) end
start_recording_session!(fixture_name_prefix)
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 25 def self.start_recording_session!(fixture_name_prefix) File.write(STORE_PATH, { fixture_name_prefix: fixture_name_prefix, new_models: [] }.to_json) end
stop_recording_session!()
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 32 def self.stop_recording_session! FileUtils.rm_f(STORE_PATH) end
Public Instance Methods
record_new_fixtures() { |lambda| ... }
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 40 def record_new_fixtures stopped = false subscriber = ActiveSupport::Notifications.subscribe 'sql.active_record' do |event| payload = event.payload next unless payload[:name] =~ /([:\w]+) Create/ new_fixture_class_name = Regexp.last_match(1) payload[:connection].transaction_manager.current_transaction.records.reject(&:persisted?).reject(&:destroyed?).each do |model_instance| next if new_fixture_class_name != model_instance.class.name @new_models << model_instance end end yield lambda { ActiveSupport::Notifications.unsubscribe(subscriber) stopped = true reload_models update_fixture_files(named_new_fixtures) } unless stopped reload_models update_fixture_files(named_new_fixtures) end ensure ActiveSupport::Notifications.unsubscribe(subscriber) end
update_recording_session()
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 72 def update_recording_session return unless FixtureRecorder.recording_session_in_progress? File.write(STORE_PATH, { fixture_name_prefix: @fixture_name_prefix, new_models: @new_models.map { |model| [model.class.name, model.id] } }.to_json) end
Private Instance Methods
datetime_erb(value)
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 165 def datetime_erb(value) beginning_of_day = value == value.beginning_of_day rounded_initial_now = round_time(@initial_now) rounded_now = round_time(Time.zone.now) if value.is_a?(Date) rounded_initial_now = rounded_initial_now.to_date rounded_now = rounded_now.to_date elsif beginning_of_day rounded_initial_now = rounded_initial_now.beginning_of_day rounded_now = rounded_now.beginning_of_day end time_travel_diff = dt_diff(rounded_initial_now, rounded_now) rounded_value = time_travel_diff.inject(value) { |sum, (part, v)| sum + v.public_send(part) } rounded_value = round_time(rounded_value) unless value.is_a?(Date) parts = dt_diff(rounded_value, rounded_initial_now) formatted_now = if value.is_a?(Date) 'Date.today' else beginning_of_day ? 'Time.zone.now.beginning_of_day' : 'Time.zone.now' end ([formatted_now] + parts.delete_if { |_, v| v.zero? }.map do |(part, v)| "#{v.positive? ? '+' : '-'} #{v.abs}.#{part.pluralize(v.abs)}" end).join(' ') end
dt_diff(left, right)
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 197 def dt_diff(left, right) units = %w[year month week day] units += %w[hour minute] unless left.is_a?(Date) units.each_with_object({ value_rest: left }) do |unit, acc| acc[unit] ||= 0 if left > right while acc[:value_rest] - 1.public_send(unit) >= right acc[unit] += 1 acc[:value_rest] -= 1.public_send(unit) end else while acc[:value_rest] + 1.public_send(unit) <= right acc[unit] -= 1 acc[:value_rest] += 1.public_send(unit) end end end.except(:value_rest) end
named_new_fixtures()
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 94 def named_new_fixtures @new_models.uniq(&:id).each_with_object({}) do |model_instance, named_new_fixtures| new_fixture_name = "#{@fixture_name_prefix}_#{model_instance.class.name.underscore.gsub('/', '_')}_1" while named_new_fixtures[new_fixture_name] new_fixture_name = new_fixture_name.sub(/_(\d+)$/, "_#{Regexp.last_match(1).to_i + 1}") end named_new_fixtures[new_fixture_name] = model_instance end end
reload_models()
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 83 def reload_models @new_models = @new_models.map do |model_instance| # reload in case model was updated after initial create model_instance.reload # Some records are created and then later removed. # We don't want to turn those into fixtures rescue ActiveRecord::RecordNotFound nil end.compact end
round_time(value)
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 155 def round_time(value) if value.to_datetime.minute == 59 value += 1.minute value = value.beginning_of_hour elsif value.to_datetime.minute == 1 || value.to_datetime.minute == 0 value = value.beginning_of_hour end value end
serialize_attributes(value)
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 142 def serialize_attributes(value) case value when ActiveSupport::TimeWithZone, Date "<%= #{datetime_erb(value)} %>" when ActiveSupport::Duration value.iso8601 when BigDecimal value.to_f else value end end
update_fixture_files(named_new_fixtures)
click to toggle source
# File lib/fixture_farm/fixture_recorder.rb, line 106 def update_fixture_files(named_new_fixtures) named_new_fixtures.each do |new_fixture_name, model_instance| attributes = model_instance.attributes yaml_attributes = attributes.except('id').compact.map do |k, v| belongs_to_association = model_instance.class.reflect_on_all_associations.filter(&:belongs_to?).find do |a| a.foreign_key.to_s == k end if belongs_to_association associated_model_instance = model_instance.public_send(belongs_to_association.name) associated_fixture_name = named_new_fixtures.find do |_, fixture_model| fixture_model.id == associated_model_instance.id end&.first || associated_model_instance.fixture_name [belongs_to_association.name.to_s, associated_fixture_name] else [k, serialize_attributes(v)] end end.to_h fixtures_file_path = model_instance.fixtures_file_path fixtures = File.exist?(fixtures_file_path) ? YAML.load_file(fixtures_file_path) : {} fixtures[new_fixture_name] = yaml_attributes FileUtils.mkdir_p(fixtures_file_path.dirname) File.open(fixtures_file_path, 'w') do |file| yaml = YAML.dump(fixtures).gsub(/\n(?=[^\s])/, "\n\n").delete_prefix("---\n\n") file.write(yaml) end end end