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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48e09d4c2f2bc2eade2e53915d3a5e6ea365b7af3774da48f72bf9ca30fd1554
4
- data.tar.gz: e451162201f818ca015827b3eb866ac87515730686cffb739fe8ca061e39800e
3
+ metadata.gz: 0daca457009dcadf8dcc794d28a0694e093671af9f2f17a121066caf45eea73a
4
+ data.tar.gz: 3e256c4e345e0975b4099f459265915af5abf69c2d34a4b95422e0083e7d26a8
5
5
  SHA512:
6
- metadata.gz: 52394f8c73eb43946a084e830b0364106b3ce5dedcc9e7155bef17b25b0a7a6df1ccbb55c2252ff64565a64d299b5db7df2c09a2c6bfa2f649c422031126b89a
7
- data.tar.gz: 273c09ddb0ef0f0b3270693c2d3eb38992ae91cd72821e1b0059198b840c8b91946aefe3ae32ca8413deeaaca5691f830fa5a5d9fff64fbd44ab1d8c4c2782aa
6
+ metadata.gz: b28b4759ba2ca263f0cc956be4dda523197039acb263d436c1a1ac6484aa7f1a08876ded66a3bf13c0e7a3214931f5926bb81d8419965f3d3c6c3156eb1c6a79
7
+ data.tar.gz: f7e50dd435f64e97e115487ccd462279a72012dec62c346a0a093645220396858eddda13cc02707259d6de5046717f0b43f2eec9ad0dfbce7a6250a5fe7be21a
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
  /tmp/
10
10
  *.gem
11
11
  .rspec_status
12
+ .idea/
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = "fixturama"
3
- gem.version = "0.0.5"
3
+ gem.version = "0.0.6"
4
4
  gem.author = "Andrew Kozin (nepalez)"
5
5
  gem.email = "andrew.kozin@gmail.com"
6
6
  gem.homepage = "https://github.com/nepalez/fixturama"
@@ -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
- extname = Pathname.new(path).extname
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
@@ -17,4 +17,10 @@ RSpec.configure do |config|
17
17
  config.expect_with :rspec do |c|
18
18
  c.syntax = :expect
19
19
  end
20
+
21
+ config.around do |example|
22
+ module Test; end
23
+ example.run
24
+ Object.send(:remove_const, :Test)
25
+ end
20
26
  end
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.5
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-04 00:00:00.000000000 Z
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