masamune 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -1
  3. data/Rakefile +37 -0
  4. data/bin/masamune-dump +22 -0
  5. data/bin/masamune-elastic-mapreduce +22 -0
  6. data/bin/masamune-hive +22 -0
  7. data/bin/masamune-psql +22 -0
  8. data/bin/masamune-shell +22 -0
  9. data/lib/masamune/cached_filesystem.rb +1 -1
  10. data/lib/masamune/commands/shell.rb +1 -1
  11. data/lib/masamune/configuration.rb +5 -7
  12. data/lib/masamune/data_plan/elem.rb +15 -7
  13. data/lib/masamune/data_plan/engine.rb +2 -0
  14. data/lib/masamune/data_plan/rule.rb +16 -5
  15. data/lib/masamune/data_plan/set.rb +8 -8
  16. data/lib/masamune/filesystem.rb +12 -6
  17. data/lib/masamune/schema/catalog.rb +6 -6
  18. data/lib/masamune/schema/column.rb +1 -1
  19. data/lib/masamune/schema/map.rb +6 -2
  20. data/lib/masamune/schema/store.rb +31 -3
  21. data/lib/masamune/tasks/shell_thor.rb +1 -1
  22. data/lib/masamune/thor.rb +12 -4
  23. data/lib/masamune/version.rb +1 -1
  24. data/lib/masamune.rb +0 -1
  25. data/spec/masamune/actions/elastic_mapreduce_spec.rb +0 -2
  26. data/spec/masamune/actions/execute_spec.rb +0 -2
  27. data/spec/masamune/actions/hadoop_filesystem_spec.rb +0 -2
  28. data/spec/masamune/actions/hadoop_streaming_spec.rb +0 -2
  29. data/spec/masamune/actions/hive_spec.rb +0 -2
  30. data/spec/masamune/actions/invoke_parallel_spec.rb +0 -2
  31. data/spec/masamune/actions/postgres_admin_spec.rb +0 -2
  32. data/spec/masamune/actions/postgres_spec.rb +0 -2
  33. data/spec/masamune/actions/s3cmd_spec.rb +0 -2
  34. data/spec/masamune/actions/transform_spec.rb +0 -2
  35. data/spec/masamune/after_initialization_callbacks_spec.rb +0 -2
  36. data/spec/masamune/cached_filesystem_spec.rb +0 -2
  37. data/spec/masamune/commands/hadoop_filesystem_spec.rb +0 -2
  38. data/spec/masamune/commands/hadoop_streaming_spec.rb +0 -2
  39. data/spec/masamune/commands/hive_spec.rb +0 -2
  40. data/spec/masamune/commands/postgres_admin_spec.rb +0 -2
  41. data/spec/masamune/commands/postgres_spec.rb +0 -2
  42. data/spec/masamune/commands/retry_with_backoff_spec.rb +0 -2
  43. data/spec/masamune/commands/s3cmd_spec.rb +0 -2
  44. data/spec/masamune/commands/shell_spec.rb +0 -2
  45. data/spec/masamune/configuration_spec.rb +12 -2
  46. data/spec/masamune/data_plan/builder_spec.rb +0 -2
  47. data/spec/masamune/data_plan/elem_spec.rb +73 -5
  48. data/spec/masamune/data_plan/engine_spec.rb +0 -2
  49. data/spec/masamune/data_plan/rule_spec.rb +51 -6
  50. data/spec/masamune/data_plan/set_spec.rb +2 -5
  51. data/spec/masamune/environment_spec.rb +0 -2
  52. data/spec/masamune/filesystem_spec.rb +33 -4
  53. data/spec/masamune/helpers/postgres_spec.rb +0 -2
  54. data/spec/masamune/rspec/job_fixture_spec.rb +365 -0
  55. data/spec/masamune/rspec/shared_example_group_spec.rb +73 -0
  56. data/spec/masamune/schema/catalog_spec.rb +14 -2
  57. data/spec/masamune/schema/column_spec.rb +0 -2
  58. data/spec/masamune/schema/dimension_spec.rb +0 -2
  59. data/spec/masamune/schema/fact_spec.rb +0 -2
  60. data/spec/masamune/schema/map_spec.rb +51 -2
  61. data/spec/masamune/schema/row_spec.rb +0 -2
  62. data/spec/masamune/schema/store_spec.rb +23 -2
  63. data/spec/masamune/schema/table_spec.rb +0 -2
  64. data/spec/masamune/string_format_spec.rb +0 -2
  65. data/spec/masamune/tasks/dump_thor_spec.rb +0 -3
  66. data/spec/masamune/tasks/elastic_mapreduce_thor_spec.rb +0 -3
  67. data/spec/masamune/tasks/hive_thor_spec.rb +0 -3
  68. data/spec/masamune/tasks/postgres_thor_spec.rb +0 -3
  69. data/spec/masamune/tasks/shell_thor_spec.rb +0 -3
  70. data/spec/masamune/template_spec.rb +0 -2
  71. data/spec/masamune/thor_spec.rb +53 -8
  72. data/spec/masamune/transform/bulk_upsert.dimension_spec.rb +0 -2
  73. data/spec/masamune/transform/consolidate_dimension_spec.rb +0 -2
  74. data/spec/masamune/transform/deduplicate_dimension_spec.rb +0 -2
  75. data/spec/masamune/transform/define_schema_spec.rb +0 -2
  76. data/spec/masamune/transform/define_table.dimension_spec.rb +0 -2
  77. data/spec/masamune/transform/define_table.fact_spec.rb +0 -2
  78. data/spec/masamune/transform/define_table.table_spec.rb +0 -2
  79. data/spec/masamune/transform/denormalize_table_spec.rb +0 -2
  80. data/spec/masamune/transform/insert_reference_values.dimension_spec.rb +0 -2
  81. data/spec/masamune/transform/insert_reference_values.fact_spec.rb +0 -2
  82. data/spec/masamune/transform/load_dimension_spec.rb +0 -2
  83. data/spec/masamune/transform/load_fact_spec.rb +0 -2
  84. data/spec/masamune/transform/relabel_dimension_spec.rb +0 -2
  85. data/spec/masamune/transform/rollup_fact_spec.rb +0 -2
  86. data/spec/masamune/transform/snapshot_dimension_spec.rb +0 -2
  87. data/spec/masamune/transform/stage_dimension_spec.rb +0 -2
  88. data/spec/masamune/transform/stage_fact_spec.rb +0 -2
  89. data/spec/masamune_spec.rb +0 -2
  90. data/spec/spec_helper.rb +2 -0
  91. data/spec/support/masamune/job_example_group.rb +62 -0
  92. data/spec/support/masamune/job_fixture.rb +137 -0
  93. data/spec/support/masamune/shared_example_group.rb +203 -0
  94. data/spec/support/masamune/step_example_group.rb +68 -0
  95. data/spec/support/masamune/step_fixture.rb +91 -0
  96. data/{lib/masamune/thor_loader.rb → spec/support/masamune/task_example_group.rb} +33 -10
  97. data/spec/support/rspec/example/action_example_group.rb +1 -1
  98. metadata +32 -3
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Template do
26
24
  describe '.render_to_file' do
27
25
  let(:parameters) { {} }
@@ -20,26 +20,37 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
- require 'thor'
25
-
26
23
  describe Masamune::Thor do
27
24
  let(:thor_class) do
28
25
  Class.new(Thor) do
29
26
  include Masamune::Thor
30
27
  include Masamune::Actions::DataFlow
31
28
 
29
+ namespace :example
30
+
32
31
  desc 'command', 'command'
33
- target path: "target/%Y-%m-%d"
34
- source path: "source/%Y%m%d*.log"
35
- method_option :zombo, desc: 'Anything is possible'
36
- def command
32
+ target path: fs.path(:tmp_dir, "target/%Y-%m-%d")
33
+ source path: fs.path(:tmp_dir, "source/%Y%m%d*.log")
34
+ def command_task
37
35
  # NOP
38
36
  end
39
37
 
40
38
  desc 'other', 'other'
41
39
  skip
42
- def other
40
+ def other_task
41
+ # NOP
42
+ end
43
+
44
+ desc 'current_dir', 'current_dir'
45
+ skip
46
+ def current_dir_task
47
+ console(fs.path(:current_dir))
48
+ end
49
+
50
+ desc 'unknown', 'unknown'
51
+ target path: fs.path(:unknown_dir, "target/%Y-%m-%d")
52
+ source path: fs.path(:unknown_dir, "source/%Y%m%d*.log")
53
+ def unknown_task
43
54
  # NOP
44
55
  end
45
56
  end
@@ -188,6 +199,40 @@ describe Masamune::Thor do
188
199
  end
189
200
  it { expect { cli_invocation }.to raise_error /random exception/ }
190
201
  end
202
+
203
+ context 'with command that raises exception during execution' do
204
+ let(:command) { 'unknown' }
205
+ let(:options) { ['--start', '2013-01-01'] }
206
+ it 'exits with status code 1 and prints error to stderr' do
207
+ expect { cli_invocation }.to raise_error { |e|
208
+ expect(e).to be_a(SystemExit)
209
+ expect(e.status).to eq(1)
210
+ }
211
+ expect(stdout.string).to be_blank
212
+ expect(stderr.string).to match(/Path :unknown_dir not defined/)
213
+ end
214
+ end
215
+
216
+ end
217
+
218
+ context 'with command that prints :current_dir' do
219
+ let(:thor_class) do
220
+ Class.new(Thor) do
221
+ include Masamune::Thor
222
+
223
+ desc 'current_dir', 'current_dir'
224
+ def current_dir
225
+ console(fs.path(:current_dir))
226
+ end
227
+ end
228
+ end
229
+
230
+ let(:command) { 'current_dir' }
231
+ it 'prints :current_dir' do
232
+ cli_invocation
233
+ expect(stdout.string).to eq(File.dirname(__FILE__) + "\n")
234
+ expect(stderr.string).to be_blank
235
+ end
191
236
  end
192
237
 
193
238
  context '.parse_extra' do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::BulkUpsert do
26
24
  before do
27
25
  allow_any_instance_of(Masamune::Schema::Table).to receive(:lock_id).and_return(42)
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::ConsolidateDimension do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::DeduplicateDimension do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::DefineSchema do
26
24
  context 'for postgres schema' do
27
25
  before do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::DefineTable do
26
24
  subject { transform.define_table(table).to_s }
27
25
 
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::DefineTable do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::DefineTable do
26
24
  let(:files) { [] }
27
25
  let(:section) { :all }
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::DenormalizeTable do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::InsertReferenceValues do
26
24
  before do
27
25
  allow_any_instance_of(Masamune::Schema::Table).to receive(:lock_id).and_return(42)
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::InsertReferenceValues do
26
24
  before do
27
25
  allow_any_instance_of(Masamune::Schema::Table).to receive(:lock_id).and_return(42)
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::LoadDimension do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::LoadFact do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::RelabelDimension do
26
24
  before do
27
25
  allow_any_instance_of(Masamune::Schema::Table).to receive(:lock_id).and_return(42)
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::RollupFact do
26
24
  before do
27
25
  allow_any_instance_of(Masamune::Schema::Table).to receive(:lock_id).and_return(42)
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::SnapshotDimension do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::StageDimension do
26
24
  before do
27
25
  catalog.schema :postgres do
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune::Transform::StageFact do
26
24
  before do
27
25
  allow_any_instance_of(Masamune::Schema::Table).to receive(:lock_id).and_return(42)
@@ -20,8 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'spec_helper'
24
-
25
23
  describe Masamune do
26
24
  it { is_expected.to be_a(Module) }
27
25
 
data/spec/spec_helper.rb CHANGED
@@ -30,6 +30,8 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
30
30
 
31
31
  require 'active_support/core_ext/string/strip'
32
32
 
33
+ ENV['MASAMUNE_ENV'] = 'test'
34
+
33
35
  Masamune::ExampleGroup.configure do |config|
34
36
  config.quiet = ENV['MASAMUNE_DEBUG'] ? false : true
35
37
  config.debug = ENV['MASAMUNE_DEBUG'] ? true : false
@@ -0,0 +1,62 @@
1
+ # The MIT License (MIT)
2
+ #
3
+ # Copyright (c) 2014-2015, VMware, Inc. All Rights Reserved.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module Masamune::JobExampleGroup
24
+ module JobFixtureContext
25
+ shared_context 'job_fixture' do |context_options = {}|
26
+ fixture_file = example_fixture_file(context_options.slice(:fixture, :file, :path))
27
+ let(:fixture) { example_fixture(file: fixture_file) }
28
+
29
+ before :all do
30
+ load_example_config!
31
+ clean_example_run!
32
+ end
33
+
34
+ before do
35
+ setup_example_input!(fixture)
36
+ end
37
+
38
+ it "should match #{fixture_file}" do
39
+ aggregate_failures 'generates expected output' do
40
+ gather_example_output(fixture) do |actual_data, expect_file, expect_data|
41
+ expect(File.exists?(expect_file)).to eq(true)
42
+ expect(actual_data).to eq(expect_data)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def self.included(base)
50
+ base.send(:include, Masamune::ExampleGroup)
51
+ base.send(:include, Masamune::SharedExampleGroup)
52
+ base.send(:include, Masamune::Actions::Filesystem)
53
+ base.send(:include, Masamune::Actions::Hive)
54
+ base.send(:include, Masamune::Actions::Postgres)
55
+ base.send(:include, JobFixtureContext)
56
+ end
57
+ end
58
+
59
+ RSpec.configure do |config|
60
+ config.include Masamune::JobExampleGroup, :type => :job, :file_path => %r{.*/spec/.*job_spec\.rb}
61
+ config.include Masamune::JobExampleGroup, :type => :task, :file_path => %r{.*/spec/.*task_spec\.rb}
62
+ end
@@ -0,0 +1,137 @@
1
+ # The MIT License (MIT)
2
+ #
3
+ # Copyright (c) 2014-2015, VMware, Inc. All Rights Reserved.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'active_support/core_ext/string/indent'
24
+
25
+ module Masamune
26
+ class JobFixture
27
+ INDENT = 2
28
+
29
+ attr_accessor :name
30
+
31
+ def initialize(options = {})
32
+ @path = options[:path]
33
+ @name = options[:name] || options[:fixture]
34
+ @file = options[:file]
35
+ @data = options[:data]
36
+ @type = options[:type]
37
+ @context = options[:context]
38
+
39
+ @data['inputs'] ||= []
40
+ @data['outputs'] ||= []
41
+ end
42
+
43
+ class << self
44
+ def load(options = {}, context = binding)
45
+ file = file_name(options)
46
+ raise ArgumentError, "Fixture '#{file}' does not exist" unless File.exists?(file)
47
+ YAML.load(ERB.new(File.read(file)).result(context)).tap do |data|
48
+ return new(options.merge(data: data, context: context))
49
+ end
50
+ end
51
+
52
+ def file_name(options = {})
53
+ return options[:file] if options[:file]
54
+ File.join(options[:path], [options[:name] || options[:fixture], suffix(options)].compact.join('.'))
55
+ end
56
+
57
+ protected
58
+
59
+ def suffix(options = {})
60
+ "#{options[:type] || 'job'}_fixture.yml"
61
+ end
62
+ end
63
+
64
+ def file_name
65
+ self.class.file_name(file: @file, path: @path, name: @name, type: @type)
66
+ end
67
+
68
+ def path
69
+ @path || File.dirname(@file)
70
+ end
71
+
72
+ def save
73
+ FileUtils.mkdir_p(path)
74
+ File.open(file_name, 'w') do |file|
75
+ file.puts '---'
76
+ file.puts 'inputs:'
77
+ @data['inputs'].each do |input|
78
+ file.puts '-'.indent(INDENT)
79
+ serialize(input) do |elem|
80
+ file.puts elem.indent(INDENT*2)
81
+ end
82
+ end
83
+ file.puts
84
+ file.puts 'outputs:'
85
+ @data['outputs'].each do |output|
86
+ file.puts '-'.indent(INDENT)
87
+ serialize(output) do |elem|
88
+ file.puts elem.indent(INDENT*2)
89
+ end
90
+ end
91
+ end
92
+ file_name
93
+ end
94
+
95
+ def inputs
96
+ @inputs ||= begin
97
+ @data['inputs'].map do |input|
98
+ if input['reference']
99
+ raise ArgumentError, "reference in #{file_name} requires fixture" unless input['reference']['fixture'] || input['reference']['file']
100
+ reference = self.class.load({path: input['reference']['path'] || path, name: input['reference']['fixture'], file: input['reference']['file'], type: @type}, @context)
101
+ section = input['reference']['section'] || 'outputs'
102
+ reference.send(section) if reference.respond_to?(section)
103
+ else
104
+ input
105
+ end
106
+ end.flatten.compact
107
+ end
108
+ end
109
+
110
+ def outputs
111
+ @data['outputs']
112
+ end
113
+
114
+ private
115
+
116
+ def serialize(hash, level = 0)
117
+ hash.each do |key, value|
118
+ case value
119
+ when String
120
+ if value.split("\n").count > 1
121
+ yield "#{key}: |".indent(level * INDENT)
122
+ value.split("\n").each do |line|
123
+ yield line.strip.indent((level + 1) * INDENT)
124
+ end
125
+ else
126
+ yield "#{key}: #{value}".indent(level * INDENT)
127
+ end
128
+ when Hash
129
+ yield "#{key}:".indent(level * INDENT)
130
+ serialize(value, level + 1) do |next_hash|
131
+ yield next_hash
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end