aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/fixture_set/file.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/fixture_set/file.rb')
-rw-r--r--activerecord/lib/active_record/fixture_set/file.rb82
1 files changed, 82 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/fixture_set/file.rb b/activerecord/lib/active_record/fixture_set/file.rb
new file mode 100644
index 0000000000..f1ea0e022f
--- /dev/null
+++ b/activerecord/lib/active_record/fixture_set/file.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require "erb"
+require "yaml"
+
+module ActiveRecord
+ class FixtureSet
+ class File # :nodoc:
+ include Enumerable
+
+ ##
+ # Open a fixture file named +file+. When called with a block, the block
+ # is called with the filehandle and the filehandle is automatically closed
+ # when the block finishes.
+ def self.open(file)
+ x = new file
+ block_given? ? yield(x) : x
+ end
+
+ def initialize(file)
+ @file = file
+ end
+
+ def each(&block)
+ rows.each(&block)
+ end
+
+ def model_class
+ config_row["model_class"]
+ end
+
+ private
+ def rows
+ @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
+ end
+
+ def config_row
+ @config_row ||= begin
+ row = raw_rows.find { |fixture_name, _| fixture_name == "_fixture" }
+ if row
+ row.last
+ else
+ { 'model_class': nil }
+ end
+ end
+ end
+
+ def raw_rows
+ @raw_rows ||= begin
+ data = YAML.load(render(IO.read(@file)))
+ data ? validate(data).to_a : []
+ rescue ArgumentError, Psych::SyntaxError => error
+ raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
+ end
+ end
+
+ def prepare_erb(content)
+ erb = ERB.new(content)
+ erb.filename = @file
+ erb
+ end
+
+ def render(content)
+ context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
+ prepare_erb(content).result(context.get_binding)
+ end
+
+ # Validate our unmarshalled data.
+ def validate(data)
+ unless Hash === data || YAML::Omap === data
+ raise Fixture::FormatError, "fixture is not a hash: #{@file}"
+ end
+
+ invalid = data.reject { |_, row| Hash === row }
+ if invalid.any?
+ raise Fixture::FormatError, "fixture key is not a hash: #{@file}, keys: #{invalid.keys.inspect}"
+ end
+ data
+ end
+ end
+ end
+end