-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support serialization of Ruby objects via ERB
You can send objects, that are __stringified by the `Object#to_s`__, into fixture loaders (seeds, stubs etc.) via ERB bindings. Those objects will be gracefully inserted into the resulting structure. ```yaml --- foo: <%= user %> ``` ```ruby let(:user) { FactoryBot.create :user } subject { load_fixture "#{__dir__}/data.yml", user: user } it { is_expected.to eq foo: user } ```
- Loading branch information
Showing
7 changed files
with
229 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# | ||
# Load fixture with some options | ||
# | ||
class Fixturama::Loader | ||
require_relative "loader/value" | ||
require_relative "loader/context" | ||
|
||
def call | ||
return load_yaml if yaml? | ||
return load_json if json? | ||
|
||
content | ||
end | ||
|
||
private | ||
|
||
def initialize(path, opts = {}) | ||
@path = path | ||
@opts = opts.to_h | ||
end | ||
|
||
def basename | ||
@basename ||= Pathname.new(@path).basename.to_s | ||
end | ||
|
||
def yaml? | ||
!basename[YAML_EXTENSION].nil? | ||
end | ||
|
||
def json? | ||
!basename[JSON_EXTENSION].nil? | ||
end | ||
|
||
def context | ||
@context ||= (yaml? || json?) ? Context.new(@opts) : Hashie::Mash.new(@opts) | ||
end | ||
|
||
def content | ||
bindings = context.instance_eval { binding } | ||
content = File.read(@path) | ||
|
||
ERB.new(content).result(bindings) | ||
end | ||
|
||
def load_yaml | ||
finalize YAML.load(content) | ||
end | ||
|
||
def load_json | ||
finalize JSON.parse(content) | ||
end | ||
|
||
# Takes the nested data loaded from YAML or JSON-formatted fixture, | ||
# and serializes its leafs to the corresponding values from a context | ||
def finalize(data) | ||
case data | ||
when Array | ||
data.map { |val| finalize(val) } | ||
when Hash | ||
data.each_with_object({}) { |(key, val), obj| obj[key] = finalize(val) } | ||
when String | ||
finalize_string(data) | ||
else | ||
data | ||
end | ||
end | ||
|
||
# Converts strings of sort `#<Fixturama::Loader::Context[:key]>` | ||
# to the corresponding value by the key | ||
# @param [String] string | ||
# @return [Object] | ||
def finalize_string(string) | ||
key = string.match(Value::MATCHER)&.captures&.first&.to_s | ||
key ? context[key] : string | ||
end | ||
|
||
# Matchers for YAML/YML/JSON in file extension like "data.yml.erb" etc. | ||
YAML_EXTENSION = /.+\.ya?ml(\.|\z)/i.freeze | ||
JSON_EXTENSION = /.+\.json(\.|\z)/i.freeze | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
class Fixturama::Loader | ||
# | ||
# The context of some fixture | ||
# | ||
class Context | ||
# Get value by key | ||
# @param [#to_s] key | ||
# @return [Object] | ||
def [](key) | ||
@values.send(key).instance_variable_get(:@value) | ||
end | ||
|
||
private | ||
|
||
def initialize(values) | ||
@values = \ | ||
Hash(values).each_with_object(Hashie::Mash.new) do |(key, val), obj| | ||
obj[key] = Value.new(key, val) | ||
end | ||
end | ||
|
||
def respond_to_missing?(name, *) | ||
@values.respond_to?(name) || super | ||
end | ||
|
||
def method_missing(name, *args) | ||
@values.respond_to?(name) ? @values.send(name, *args) : super | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
class Fixturama::Loader | ||
# | ||
# Wraps a value with a reference to its key | ||
# in the [Fixturama::Loader::Context] | ||
# | ||
class Value | ||
# Regex mather to extract value key from the stringified wrapper | ||
MATCHER = /\A\#\<Fixturama::Loader::Context\[([^\]]+)\]\>\z/.freeze | ||
|
||
def self.new(key, value) | ||
case value | ||
when String, Symbol, Numeric, TrueClass, FalseClass, NilClass then value | ||
else super | ||
end | ||
end | ||
|
||
# The sting representing the value with a reference to it in bindings | ||
def to_s | ||
"\"#<Fixturama::Loader::Context[#{@key}]>\"" | ||
end | ||
alias to_str to_s | ||
|
||
private | ||
|
||
def initialize(key, value) | ||
@key = key | ||
@value = value | ||
end | ||
|
||
def method_missing(name, *args, &block) | ||
@value.respond_to?(name) ? @value.send(name, *args, &block) : super | ||
end | ||
|
||
def respond_to_missing?(name, *) | ||
@value.respond_to?(name) || super | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters