fixturama 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +51 -0
- data/README.md +33 -0
- data/fixturama.gemspec +1 -1
- data/lib/fixturama/loader/context.rb +30 -0
- data/lib/fixturama/loader/value.rb +38 -0
- data/lib/fixturama/loader.rb +80 -0
- data/lib/fixturama.rb +2 -6
- data/spec/fixturama/load_fixture/_spec.rb +32 -0
- data/spec/spec_helper.rb +6 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0daca457009dcadf8dcc794d28a0694e093671af9f2f17a121066caf45eea73a
|
4
|
+
data.tar.gz: 3e256c4e345e0975b4099f459265915af5abf69c2d34a4b95422e0083e7d26a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b28b4759ba2ca263f0cc956be4dda523197039acb263d436c1a1ac6484aa7f1a08876ded66a3bf13c0e7a3214931f5926bb81d8419965f3d3c6c3156eb1c6a79
|
7
|
+
data.tar.gz: f7e50dd435f64e97e115487ccd462279a72012dec62c346a0a093645220396858eddda13cc02707259d6de5046717f0b43f2eec9ad0dfbce7a6250a5fe7be21a
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,56 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
7
7
|
|
8
|
+
## [0.0.6] - [2019-06-09]
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- Better matching of YAML/JSON files (nepalez)
|
13
|
+
|
14
|
+
The loader recognizes complex extensions like `data.yml.erb`
|
15
|
+
or `data.json.erb`, as well as `data.YAML` in upper register.
|
16
|
+
|
17
|
+
- Support for Ruby objects (including Activerecord models) serialization
|
18
|
+
in the parameters of fixtures (nepalez)
|
19
|
+
|
20
|
+
You can send objects, that are stringified in a default Ruby way,
|
21
|
+
into fixture loaders (seeds, stubs etc.) via ERB bindings.
|
22
|
+
Those objects will be gracefully inserted into the resulting structure:
|
23
|
+
|
24
|
+
```yaml
|
25
|
+
---
|
26
|
+
:account: <%= user %>
|
27
|
+
```
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
let(:user) { FactoryBot.create :user }
|
31
|
+
subject { load_fixture "#{__dir__}/output.yml", user: user }
|
32
|
+
|
33
|
+
# The `user` object has been bound via ERB
|
34
|
+
it { is_expected.to eq account: user }
|
35
|
+
```
|
36
|
+
|
37
|
+
This feature can be used for adding RSpec [matching arguments](https://relishapp.com/rspec/rspec-mocks/v/3-8/docs/setting-constraints/matching-arguments):
|
38
|
+
|
39
|
+
```yaml
|
40
|
+
---
|
41
|
+
:foo: <%= foo %>
|
42
|
+
:bar: 3
|
43
|
+
```
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
# Use the RSpec `anyting` matcher
|
47
|
+
subject { { foo: 4, bar: 3 } }
|
48
|
+
|
49
|
+
let(:template) { load_fixture "#{__dir__}/template.yml", foo: anyting }
|
50
|
+
|
51
|
+
# The `anyting` has been bound via ERB to the template
|
52
|
+
# Compare `{ foo: 4, bar: 3 }` to the template `{ foo: anything, bar: 3 }`
|
53
|
+
it { is_expected.to include(template) }
|
54
|
+
```
|
55
|
+
|
56
|
+
**Be careful though**: the trick won't work with objects whose default method `Object#to_s` has been overloaded.
|
57
|
+
|
8
58
|
## [0.0.5] - [2018-06-04]
|
9
59
|
|
10
60
|
### Added
|
@@ -82,3 +132,4 @@ This is a first public release with features extracted from production app.
|
|
82
132
|
[0.0.3]: https://github.com/nepalez/fixturama/compare/v0.0.2...v0.0.3
|
83
133
|
[0.0.4]: https://github.com/nepalez/fixturama/compare/v0.0.3...v0.0.4
|
84
134
|
[0.0.5]: https://github.com/nepalez/fixturama/compare/v0.0.4...v0.0.5
|
135
|
+
[0.0.6]: https://github.com/nepalez/fixturama/compare/v0.0.5...v0.0.6
|
data/README.md
CHANGED
@@ -42,6 +42,8 @@ The gem defines 3 helpers (support ERB bindings):
|
|
42
42
|
- `seed_fixture(path_to_yaml, **opts)` to prepare database using the [FactoryBot][factory-bot]
|
43
43
|
- `stub_fixture(path_to_yaml, **opts)` to stub some classes
|
44
44
|
|
45
|
+
### Loading
|
46
|
+
|
45
47
|
```ruby
|
46
48
|
# spec/models/user/_spec.rb
|
47
49
|
RSpec.describe "GraphQL mutation 'deleteProfile'" do
|
@@ -71,6 +73,34 @@ RSpec.describe "GraphQL mutation 'deleteProfile'" do
|
|
71
73
|
end
|
72
74
|
```
|
73
75
|
|
76
|
+
Notice, that since the `v0.0.6` the gem also supports binding any ruby object, not only strings, booleans and numbers:
|
77
|
+
|
78
|
+
```yaml
|
79
|
+
# ./data.yml
|
80
|
+
---
|
81
|
+
account: <%= user %>
|
82
|
+
```
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# Bind activerecord model
|
86
|
+
subject { load_fixture "#{__dir__}/data.yml", user: user }
|
87
|
+
|
88
|
+
let(:user) { FactoryBot.create :user }
|
89
|
+
|
90
|
+
# The same object will be returned
|
91
|
+
it { is_expected.to eq account: user }
|
92
|
+
```
|
93
|
+
|
94
|
+
The object must be named in the options you send to the `load_fixture`, `stub_fixture`, or `seed_fixture` helpers.
|
95
|
+
|
96
|
+
This feature can also be useful to produce a "partially defined" fixtures with [RSpec argument matchers][rspec-argument-matchers]:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
subject { load_fixture "#{__dir__}/data.yml", user: kind_of(ActiveRecord::Base) }
|
100
|
+
```
|
101
|
+
|
102
|
+
### Seeding
|
103
|
+
|
74
104
|
The seed (`seed_fixture`) file should be a YAML/JSON with opinionated parameters, namely:
|
75
105
|
|
76
106
|
- `type` for the name of the [FactoryBot][factory-bot] factory
|
@@ -92,6 +122,8 @@ The seed (`seed_fixture`) file should be a YAML/JSON with opinionated parameters
|
|
92
122
|
|
93
123
|
Use the `count: 2` key to create more objects at once.
|
94
124
|
|
125
|
+
### Stubbing
|
126
|
+
|
95
127
|
Another opinionated format we use for stubs (`stub_fixture`). The gem supports stubbing both message chains and constants.
|
96
128
|
|
97
129
|
For message chains:
|
@@ -181,3 +213,4 @@ The gem is available as open source under the terms of the [MIT License][license
|
|
181
213
|
[factory-bot]: https://github.com/thoughtbot/factory_bot
|
182
214
|
[rspec]: https://rspec.info/
|
183
215
|
[dev_to]: https://dev.to/evilmartians/a-fixture-based-approach-to-interface-testing-in-rails-2cd4
|
216
|
+
[rspec-argument-matchers]: https://relishapp.com/rspec/rspec-mocks/v/3-8/docs/setting-constraints/matching-arguments
|
data/fixturama.gemspec
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
class Fixturama::Loader
|
2
|
+
#
|
3
|
+
# The context of some fixture
|
4
|
+
#
|
5
|
+
class Context
|
6
|
+
# Get value by key
|
7
|
+
# @param [#to_s] key
|
8
|
+
# @return [Object]
|
9
|
+
def [](key)
|
10
|
+
@values.send(key).instance_variable_get(:@value)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def initialize(values)
|
16
|
+
@values = \
|
17
|
+
Hash(values).each_with_object(Hashie::Mash.new) do |(key, val), obj|
|
18
|
+
obj[key] = Value.new(key, val)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to_missing?(name, *)
|
23
|
+
@values.respond_to?(name) || super
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(name, *args)
|
27
|
+
@values.respond_to?(name) ? @values.send(name, *args) : super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Fixturama::Loader
|
2
|
+
#
|
3
|
+
# Wraps a value with a reference to its key
|
4
|
+
# in the [Fixturama::Loader::Context]
|
5
|
+
#
|
6
|
+
class Value
|
7
|
+
# Regex mather to extract value key from the stringified wrapper
|
8
|
+
MATCHER = /\A\#\<Fixturama::Loader::Context\[([^\]]+)\]\>\z/.freeze
|
9
|
+
|
10
|
+
def self.new(key, value)
|
11
|
+
case value
|
12
|
+
when String, Symbol, Numeric, TrueClass, FalseClass, NilClass then value
|
13
|
+
else super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# The sting representing the value with a reference to it in bindings
|
18
|
+
def to_s
|
19
|
+
"\"#<Fixturama::Loader::Context[#{@key}]>\""
|
20
|
+
end
|
21
|
+
alias to_str to_s
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def initialize(key, value)
|
26
|
+
@key = key
|
27
|
+
@value = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(name, *args, &block)
|
31
|
+
@value.respond_to?(name) ? @value.send(name, *args, &block) : super
|
32
|
+
end
|
33
|
+
|
34
|
+
def respond_to_missing?(name, *)
|
35
|
+
@value.respond_to?(name) || super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#
|
2
|
+
# Load fixture with some options
|
3
|
+
#
|
4
|
+
class Fixturama::Loader
|
5
|
+
require_relative "loader/value"
|
6
|
+
require_relative "loader/context"
|
7
|
+
|
8
|
+
def call
|
9
|
+
return load_yaml if yaml?
|
10
|
+
return load_json if json?
|
11
|
+
|
12
|
+
content
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def initialize(path, opts = {})
|
18
|
+
@path = path
|
19
|
+
@opts = opts.to_h
|
20
|
+
end
|
21
|
+
|
22
|
+
def basename
|
23
|
+
@basename ||= Pathname.new(@path).basename.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def yaml?
|
27
|
+
!basename[YAML_EXTENSION].nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def json?
|
31
|
+
!basename[JSON_EXTENSION].nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
def context
|
35
|
+
@context ||= (yaml? || json?) ? Context.new(@opts) : Hashie::Mash.new(@opts)
|
36
|
+
end
|
37
|
+
|
38
|
+
def content
|
39
|
+
bindings = context.instance_eval { binding }
|
40
|
+
content = File.read(@path)
|
41
|
+
|
42
|
+
ERB.new(content).result(bindings)
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_yaml
|
46
|
+
finalize YAML.load(content)
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_json
|
50
|
+
finalize JSON.parse(content)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Takes the nested data loaded from YAML or JSON-formatted fixture,
|
54
|
+
# and serializes its leafs to the corresponding values from a context
|
55
|
+
def finalize(data)
|
56
|
+
case data
|
57
|
+
when Array
|
58
|
+
data.map { |val| finalize(val) }
|
59
|
+
when Hash
|
60
|
+
data.each_with_object({}) { |(key, val), obj| obj[key] = finalize(val) }
|
61
|
+
when String
|
62
|
+
finalize_string(data)
|
63
|
+
else
|
64
|
+
data
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Converts strings of sort `#<Fixturama::Loader::Context[:key]>`
|
69
|
+
# to the corresponding value by the key
|
70
|
+
# @param [String] string
|
71
|
+
# @return [Object]
|
72
|
+
def finalize_string(string)
|
73
|
+
key = string.match(Value::MATCHER)&.captures&.first&.to_s
|
74
|
+
key ? context[key] : string
|
75
|
+
end
|
76
|
+
|
77
|
+
# Matchers for YAML/YML/JSON in file extension like "data.yml.erb" etc.
|
78
|
+
YAML_EXTENSION = /.+\.ya?ml(\.|\z)/i.freeze
|
79
|
+
JSON_EXTENSION = /.+\.json(\.|\z)/i.freeze
|
80
|
+
end
|
data/lib/fixturama.rb
CHANGED
@@ -8,6 +8,7 @@ require "yaml"
|
|
8
8
|
module Fixturama
|
9
9
|
require_relative "fixturama/config"
|
10
10
|
require_relative "fixturama/utils"
|
11
|
+
require_relative "fixturama/loader"
|
11
12
|
require_relative "fixturama/stubs"
|
12
13
|
require_relative "fixturama/seed"
|
13
14
|
|
@@ -28,12 +29,7 @@ module Fixturama
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def load_fixture(path, **opts)
|
31
|
-
|
32
|
-
|
33
|
-
read_fixture(path, **opts).tap do |content|
|
34
|
-
return YAML.load(content) if %w[.yaml .yml].include?(extname)
|
35
|
-
return JSON.parse(content) if extname == ".json"
|
36
|
-
end
|
32
|
+
Loader.new(path, opts).call
|
37
33
|
end
|
38
34
|
|
39
35
|
def read_fixture(path, **opts)
|
@@ -13,9 +13,41 @@ RSpec.describe "load_fixture" do
|
|
13
13
|
it { is_expected.to eq expected }
|
14
14
|
end
|
15
15
|
|
16
|
+
context "YAML with ruby object" do
|
17
|
+
subject { load_fixture("#{__dir__}/data.yaml", id: foobar) }
|
18
|
+
|
19
|
+
before { class Test::Foobar; end }
|
20
|
+
|
21
|
+
let(:foobar) { Test::Foobar.new }
|
22
|
+
let(:expected) { { "foo" => { "bar" => foobar } } }
|
23
|
+
|
24
|
+
it { is_expected.to eq expected }
|
25
|
+
end
|
26
|
+
|
16
27
|
context "JSON" do
|
17
28
|
subject { load_fixture("#{__dir__}/data.json", id: 42) }
|
18
29
|
|
19
30
|
it { is_expected.to eq expected }
|
20
31
|
end
|
32
|
+
|
33
|
+
context "JSON with ruby object" do
|
34
|
+
subject { load_fixture("#{__dir__}/data.json", id: foobar) }
|
35
|
+
|
36
|
+
before { class Test::Foobar; end }
|
37
|
+
|
38
|
+
let(:foobar) { Test::Foobar.new }
|
39
|
+
let(:expected) { { "foo" => { "bar" => foobar } } }
|
40
|
+
|
41
|
+
it { is_expected.to eq expected }
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with RSpec argument matchers" do
|
45
|
+
subject { load_fixture("#{__dir__}/data.yaml", id: kind_of(Numeric)) }
|
46
|
+
|
47
|
+
it "loads the matcher", aggregate_failures: true do
|
48
|
+
expect("foo" => { "bar" => 42 }).to include subject
|
49
|
+
expect("foo" => { "bar" => 99 }).to include subject
|
50
|
+
expect("foo" => { "bar" => :a }).not_to include subject
|
51
|
+
end
|
52
|
+
end
|
21
53
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fixturama
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kozin (nepalez)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: factory_bot
|
@@ -114,6 +114,9 @@ files:
|
|
114
114
|
- fixturama.gemspec
|
115
115
|
- lib/fixturama.rb
|
116
116
|
- lib/fixturama/config.rb
|
117
|
+
- lib/fixturama/loader.rb
|
118
|
+
- lib/fixturama/loader/context.rb
|
119
|
+
- lib/fixturama/loader/value.rb
|
117
120
|
- lib/fixturama/rspec.rb
|
118
121
|
- lib/fixturama/seed.rb
|
119
122
|
- lib/fixturama/stubs.rb
|