polytrix 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop-todo.yml +14 -5
  3. data/Gemfile +2 -1
  4. data/README.md +139 -177
  5. data/Rakefile +5 -12
  6. data/bin/polytrix +0 -1
  7. data/features/bootstrapping.feature +0 -3
  8. data/features/cloning.feature +0 -3
  9. data/features/show.feature +38 -0
  10. data/features/states.feature +12 -13
  11. data/features/step_definitions/sdk_steps.rb +0 -4
  12. data/lib/polytrix/challenge.rb +135 -53
  13. data/lib/polytrix/challenge_result.rb +0 -2
  14. data/lib/polytrix/challenge_runner.rb +28 -18
  15. data/lib/polytrix/cli.rb +53 -69
  16. data/lib/polytrix/color.rb +2 -2
  17. data/lib/polytrix/command/action.rb +4 -3
  18. data/lib/polytrix/command/list.rb +39 -28
  19. data/lib/polytrix/command/report.rb +9 -86
  20. data/lib/polytrix/command/reports/code2doc.rb +72 -0
  21. data/lib/polytrix/command/reports/dashboard.rb +125 -0
  22. data/lib/polytrix/command/show.rb +148 -0
  23. data/lib/polytrix/command.rb +37 -104
  24. data/lib/polytrix/configuration.rb +14 -18
  25. data/lib/polytrix/{core/hashie.rb → dash.rb} +4 -3
  26. data/lib/polytrix/documentation/code_segmenter.rb +8 -8
  27. data/lib/polytrix/documentation/comment_styles.rb +1 -1
  28. data/lib/polytrix/documentation/helpers/code_helper.rb +9 -0
  29. data/lib/polytrix/documentation_generator.rb +11 -14
  30. data/lib/polytrix/error.rb +104 -97
  31. data/lib/polytrix/executor.rb +33 -0
  32. data/lib/polytrix/{runners → executors}/buff_shellout_executor.rb +1 -1
  33. data/lib/polytrix/executors/linux_challenge_executor.rb +29 -0
  34. data/lib/polytrix/executors/mixlib_shellout_executor.rb +55 -0
  35. data/lib/polytrix/{runners/windows_challenge_runner.rb → executors/windows_challenge_executor.rb} +4 -11
  36. data/lib/polytrix/{core/implementor.rb → implementor.rb} +10 -6
  37. data/lib/polytrix/manifest.rb +2 -31
  38. data/lib/polytrix/{reports → reporters}/hash_reporter.rb +6 -2
  39. data/lib/polytrix/{reports → reporters}/json_reporter.rb +2 -2
  40. data/lib/polytrix/{reports → reporters}/markdown_reporter.rb +7 -2
  41. data/lib/polytrix/{reports → reporters}/yaml_reporter.rb +2 -2
  42. data/lib/polytrix/reporters.rb +27 -0
  43. data/lib/polytrix/result.rb +6 -5
  44. data/lib/polytrix/spies/file_system_spy.rb +15 -0
  45. data/lib/polytrix/spies.rb +61 -0
  46. data/lib/polytrix/state_file.rb +1 -20
  47. data/lib/polytrix/util.rb +157 -62
  48. data/lib/polytrix/validation.rb +41 -2
  49. data/lib/polytrix/validator.rb +9 -4
  50. data/lib/polytrix/version.rb +1 -1
  51. data/lib/polytrix.rb +110 -105
  52. data/polytrix.gemspec +7 -2
  53. data/polytrix.yml +16 -13
  54. data/resources/assets/pygments/autumn.css +58 -0
  55. data/resources/assets/pygments/borland.css +46 -0
  56. data/resources/assets/pygments/bw.css +34 -0
  57. data/resources/assets/pygments/colorful.css +61 -0
  58. data/resources/assets/pygments/default.css +62 -0
  59. data/resources/assets/pygments/emacs.css +61 -0
  60. data/resources/assets/pygments/friendly.css +61 -0
  61. data/resources/assets/pygments/fruity.css +69 -0
  62. data/resources/assets/pygments/github.css +61 -0
  63. data/resources/assets/pygments/manni.css +61 -0
  64. data/resources/assets/pygments/monokai.css +64 -0
  65. data/resources/assets/pygments/murphy.css +61 -0
  66. data/resources/assets/pygments/native.css +69 -0
  67. data/resources/assets/pygments/pastie.css +60 -0
  68. data/resources/assets/pygments/perldoc.css +58 -0
  69. data/resources/assets/pygments/tango.css +69 -0
  70. data/resources/assets/pygments/trac.css +59 -0
  71. data/resources/assets/pygments/vim.css +69 -0
  72. data/resources/assets/pygments/vs.css +33 -0
  73. data/resources/assets/pygments/zenburn.css +1 -0
  74. data/resources/assets/style.css +41 -0
  75. data/resources/templates/dashboard/files/dashboard.html.tt +82 -0
  76. data/resources/templates/dashboard/templates/_test_report.html.tt +87 -0
  77. data/samples/bootstrap.sh +2 -0
  78. data/samples/clone.sh +2 -0
  79. data/samples/code2doc.sh +4 -0
  80. data/samples/docs/samples/code2doc/java/katas-hello_world-java.md +17 -0
  81. data/samples/docs/samples/code2doc/java/katas-quine-java.md +35 -0
  82. data/samples/docs/samples/code2doc/python/katas-hello_world-python.md +5 -0
  83. data/samples/docs/samples/code2doc/python/katas-quine-python.md +6 -0
  84. data/samples/docs/samples/code2doc/ruby/katas-hello_world-ruby.md +11 -0
  85. data/samples/exec.sh +2 -0
  86. data/samples/polytrix.rb +2 -2
  87. data/samples/polytrix.yml +5 -2
  88. data/samples/show.sh +4 -0
  89. data/samples/test.sh +2 -0
  90. data/samples/tests/polytrix/validators.rb +2 -2
  91. data/samples/verify.sh +3 -0
  92. data/scripts/wrapper +4 -7
  93. data/spec/fabricators/challenge_fabricator.rb +2 -9
  94. data/spec/fabricators/implementor_fabricator.rb +0 -8
  95. data/spec/fabricators/manifest_fabricator.rb +2 -9
  96. data/spec/fabricators/validator_fabricator.rb +2 -4
  97. data/spec/polytrix/challenge_runner_spec.rb +20 -0
  98. data/spec/polytrix/documentation/helpers/code_helper_spec.rb +7 -7
  99. data/spec/polytrix/file_finder_spec.rb +5 -5
  100. data/spec/polytrix/manifest_spec.rb +0 -21
  101. data/spec/polytrix/result_spec.rb +14 -14
  102. data/spec/polytrix/validator_registry_spec.rb +4 -4
  103. data/spec/polytrix/validator_spec.rb +9 -9
  104. data/spec/polytrix_spec.rb +1 -25
  105. data/spec/spec_helper.rb +8 -1
  106. metadata +130 -38
  107. data/features/execution.feature +0 -53
  108. data/features/fixtures/spec/polytrix_spec.rb +0 -7
  109. data/lib/polytrix/cli/report.rb +0 -84
  110. data/lib/polytrix/command/rundoc.rb +0 -27
  111. data/lib/polytrix/core/file_system_helper.rb +0 -75
  112. data/lib/polytrix/core/manifest_section.rb +0 -4
  113. data/lib/polytrix/core/string_helpers.rb +0 -15
  114. data/lib/polytrix/documentation/view_helper.rb +0 -21
  115. data/lib/polytrix/rspec/documentation_formatter.rb +0 -66
  116. data/lib/polytrix/rspec/yaml_report.rb +0 -51
  117. data/lib/polytrix/rspec.rb +0 -56
  118. data/lib/polytrix/runners/executor.rb +0 -34
  119. data/lib/polytrix/runners/linux_challenge_runner.rb +0 -23
  120. data/lib/polytrix/runners/middleware/change_directory.rb +0 -20
  121. data/lib/polytrix/runners/middleware/feature_executor.rb +0 -24
  122. data/lib/polytrix/runners/middleware/setup_env_vars.rb +0 -42
  123. data/lib/polytrix/runners/mixlib_shellout_executor.rb +0 -83
  124. data/lib/polytrix/validations.rb +0 -23
  125. data/samples/scripts/wrapper +0 -7
  126. data/spec/polytrix/middleware/feature_executor_spec.rb +0 -48
  127. data/spec/polytrix/validations_spec.rb +0 -16
@@ -1,7 +1,7 @@
1
1
  require 'buff/shell_out'
2
2
 
3
3
  module Polytrix
4
- module Runners
4
+ module Executors
5
5
  class BuffShellOutExecutor
6
6
  def execute(command, opts)
7
7
  cwd = opts.delete(:cwd) || Dir.pwd
@@ -0,0 +1,29 @@
1
+ module Polytrix
2
+ module Executors
3
+ class LinuxChallengeRunner < ChallengeRunner
4
+ include Polytrix::Util::FileSystem
5
+
6
+ def challenge_command(challenge_script, basedir = Dir.pwd)
7
+ challenge_script = "./#{challenge_script}" unless challenge_script.to_s.start_with? '/'
8
+
9
+ [wrapper_script(basedir), challenge_script].compact.join(' ')
10
+ end
11
+
12
+ protected
13
+
14
+ def wrapper_script(basedir)
15
+ basedir_relative_wrapper = File.expand_path('scripts/wrapper', basedir)
16
+ root_relative_wrapper = File.expand_path('scripts/wrapper', Dir.pwd)
17
+
18
+ if File.exist? basedir_relative_wrapper
19
+ relativize(basedir_relative_wrapper, basedir).to_s
20
+ elsif File.exist? root_relative_wrapper
21
+ # FIXME: This isn't always desired, probably better to opt-in to this behavior
22
+ relativize(root_relative_wrapper, basedir).to_s
23
+ else
24
+ nil
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,55 @@
1
+ require 'mixlib/shellout'
2
+
3
+ module Polytrix
4
+ module Executors
5
+ class IOToLog < IO
6
+ def initialize(logger)
7
+ @logger = logger
8
+ @buffer = ''
9
+ end
10
+
11
+ def write(string)
12
+ (@buffer + string).lines.each do |line|
13
+ if line.end_with? "\n"
14
+ @buffer = ''
15
+ @logger.info(line.rstrip)
16
+ else
17
+ @buffer = line
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ class MixlibShellOutExecutor
24
+ include Polytrix::DefaultLogger
25
+
26
+ MIXLIB_SHELLOUT_EXCEPTION_CLASSES = Mixlib::ShellOut.constants.map do|name|
27
+ klass = Mixlib::ShellOut.const_get(name)
28
+ if klass.is_a?(Class) && klass <= RuntimeError
29
+ klass
30
+ else
31
+ nil
32
+ end
33
+ end.compact
34
+
35
+ def log_decorator(_io, _prefix)
36
+ IOToLog.new(logger)
37
+ end
38
+
39
+ def execute(command, opts)
40
+ prefix = opts.delete :prefix
41
+ shell = Mixlib::ShellOut.new(command, opts)
42
+ shell.live_stream = log_decorator $stdout, prefix
43
+ shell.run_command
44
+ execution_result = ExecutionResult.new exitstatus: shell.exitstatus, stdout: shell.stdout, stderr: shell.stderr
45
+ # shell.error!
46
+ execution_result
47
+ rescue SystemCallError, *MIXLIB_SHELLOUT_EXCEPTION_CLASSES, TypeError => e
48
+ # See https://github.com/opscode/mixlib-shellout/issues/62
49
+ execution_error = ExecutionError.new(e)
50
+ execution_error.execution_result = execution_result
51
+ raise execution_error
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,25 +1,18 @@
1
1
  module Polytrix
2
- module Runners
2
+ module Executors
3
3
  class WindowsChallengeRunner < ChallengeRunner
4
4
  PS_OPTIONS = '-NoProfile -ExecutionPolicy Bypass'
5
- def script_extension
6
- 'ps1'
7
- end
8
5
 
9
- def challenge_command(env_file, challenge_script)
6
+ def challenge_command(challenge_script, _basedir = Dir.pwd)
10
7
  # I don't know a simple powershell replacement for &&
11
8
  # See http://stackoverflow.com/questions/2416662/what-are-the-powershell-equivalent-of-bashs-and-operators
12
9
  if File.exist? 'scripts/wrapper.ps1'
13
- command = ". ./#{env_file}; ./scripts/wrapper.ps1 #{challenge_script}"
10
+ command = "./scripts/wrapper.ps1 #{challenge_script}"
14
11
  else
15
- command = ". ./#{env_file}; ./#{challenge_script}"
12
+ command = "./#{challenge_script}"
16
13
  end
17
14
  "PowerShell #{PS_OPTIONS} -Command \"#{command}\""
18
15
  end
19
-
20
- def save_environment_variable(key, value)
21
- "$Env:#{key}='#{value}'"
22
- end
23
16
  end
24
17
  end
25
18
  end
@@ -20,8 +20,8 @@ module Polytrix
20
20
  end
21
21
 
22
22
  include Polytrix::Logging
23
- include Polytrix::Core::FileSystemHelper
24
- include Polytrix::Runners::Executor
23
+ include Polytrix::Util::FileSystem
24
+ include Executor
25
25
  property :name
26
26
  property :basedir, required: true
27
27
  property :language
@@ -46,7 +46,7 @@ module Polytrix
46
46
  end
47
47
  branch = git.branch ||= 'master'
48
48
  target_dir = git.to ||= basedir
49
- if File.exists? target_dir
49
+ if File.exist? target_dir
50
50
  logger.info "Skipping clone because #{target_dir} already exists"
51
51
  else
52
52
  clone_cmd = "git clone #{git.repo} -b #{branch} #{target_dir}"
@@ -61,8 +61,12 @@ module Polytrix
61
61
  fail "Implementor #{name} has not been cloned" unless cloned?
62
62
 
63
63
  execute('./scripts/bootstrap', cwd: basedir, prefix: name)
64
- rescue Errno::ENOENT
65
- logger.warn "Skipping bootstrapping for #{name}, no script/bootstrap exists"
64
+ rescue ExecutionError => e
65
+ if e.cause.is_a? Errno::ENOENT
66
+ logger.warn "Skipping bootstrapping for #{name}, no script/bootstrap exists"
67
+ else
68
+ raise e
69
+ end
66
70
  end
67
71
 
68
72
  def build_challenge(challenge_data)
@@ -72,7 +76,7 @@ module Polytrix
72
76
  begin
73
77
  challenge_data[:source_file] ||= find_file basedir, challenge_data[:name]
74
78
  challenge_data[:source_file] = relativize(challenge_data[:source_file], challenge_data[:basedir])
75
- rescue Polytrix::Core::FileSystemHelper::FileNotFound
79
+ rescue Errno::ENOENT
76
80
  challenge_data[:source_file] = nil
77
81
  end
78
82
  Challenge.new challenge_data
@@ -1,5 +1,4 @@
1
1
  require 'yaml'
2
- require 'hashie/dash'
3
2
  require 'hashie/mash'
4
3
  require 'hashie/extensions/coercion'
5
4
  require 'hashie/extensions/deep_merge'
@@ -49,19 +48,10 @@ module Polytrix
49
48
  coerce_value Integer, String
50
49
  end
51
50
 
52
- class CodeSample < Polytrix::ManifestSection
53
- property :name, required: true
54
-
55
- def self.coerce(data)
56
- data = { name: data } if data.is_a? String
57
- new(data)
58
- end
59
- end
60
-
61
51
  class Suite < Polytrix::ManifestSection
62
52
  property :env, default: {}
63
53
  property :samples, required: true
64
- coerce_key :samples, Array[CodeSample]
54
+ coerce_key :samples, Array[String]
65
55
  property :results
66
56
  end
67
57
 
@@ -80,7 +70,7 @@ module Polytrix
80
70
  suites.each do | suite_name, suite |
81
71
  suite.samples.each do | sample |
82
72
  implementors.each_value do | implementor |
83
- challenge = implementor.build_challenge suite: suite_name, name: sample.name, vars: suite.env
73
+ challenge = implementor.build_challenge suite: suite_name, name: sample, vars: suite.env
84
74
  @challenges[challenge.slug] = challenge
85
75
  end
86
76
  end
@@ -96,24 +86,5 @@ module Polytrix
96
86
  data = YAML.load processed_content
97
87
  new data
98
88
  end
99
-
100
- def find_suite(suite_name)
101
- _, suite = suites.find { |name, _| name.to_s.downcase == suite_name.to_s.downcase }
102
- suite
103
- end
104
-
105
- def find_challenge(suite_name, scenario_name)
106
- suite = find_suite suite_name
107
- return nil if suite.nil?
108
-
109
- if suite.samples.is_a? Array
110
- # No results yet
111
- suite.samples.find { |name, _| name.downcase == scenario_name.downcase }
112
- Challenge.new suite: suite_name, name: scenario_name
113
- else
114
- _, challenge_data = find_suite('identity').samples.find { |name, challenge| name.downcase == scenario_name.downcase }
115
- Challenge.new(suite: suite_name, name: scenario_name, result: challenge_data)
116
- end
117
- end
118
89
  end
119
90
  end
@@ -1,7 +1,7 @@
1
1
  require 'csv'
2
2
 
3
3
  module Polytrix
4
- module Reports
4
+ module Reporters
5
5
  class HashReporter
6
6
  def initialize(io = $stdout)
7
7
  @buffer = io
@@ -20,9 +20,13 @@ module Polytrix
20
20
  @buffer.puts convert(data)
21
21
  end
22
22
 
23
- def convert(data)
23
+ def convert(_data)
24
24
  fail 'Subclass HashReporter and convert the data to the target format'
25
25
  end
26
+
27
+ def colors?
28
+ false
29
+ end
26
30
  end
27
31
  end
28
32
  end
@@ -1,8 +1,8 @@
1
1
  require 'json'
2
- require 'polytrix/cli/reports/hash_reporter'
2
+ require 'polytrix/reporters/hash_reporter'
3
3
 
4
4
  module Polytrix
5
- module Reports
5
+ module Reporters
6
6
  class JSONReporter < HashReporter
7
7
  def convert(data)
8
8
  JSON.pretty_generate data
@@ -1,6 +1,7 @@
1
1
  module Polytrix
2
- module Reports
2
+ module Reporters
3
3
  class MarkdownReporter
4
+ include Polytrix::Util::String
4
5
  def initialize(io = $stdout)
5
6
  @buffer = io
6
7
  end
@@ -13,9 +14,13 @@ module Polytrix
13
14
  @buffer.puts header_line.gsub(/[^|]/, '-')
14
15
 
15
16
  table[1..-1].each do |data_line|
16
- @buffer.puts data_line.join ' | '
17
+ @buffer.puts data_line.map { |line| escape_html(line) }.join(' | ')
17
18
  end
18
19
  end
20
+
21
+ def colors?
22
+ false
23
+ end
19
24
  end
20
25
  end
21
26
  end
@@ -1,8 +1,8 @@
1
1
  require 'yaml'
2
- require 'polytrix/cli/reports/hash_reporter'
2
+ require 'polytrix/reporters/hash_reporter'
3
3
 
4
4
  module Polytrix
5
- module Reports
5
+ module Reporters
6
6
  class YAMLReporter < HashReporter
7
7
  def convert(data)
8
8
  YAML.dump data
@@ -0,0 +1,27 @@
1
+ module Polytrix
2
+ module Reporters
3
+ autoload :MarkdownReporter, 'polytrix/reporters/markdown_reporter'
4
+ # autoload :HTMLReporter, 'polytrix/reporters/html_reporter'
5
+ autoload :JSONReporter, 'polytrix/reporters/json_reporter'
6
+ autoload :YAMLReporter, 'polytrix/reporters/yaml_reporter'
7
+
8
+ RESOURCES_DIR = File.expand_path '../../../resources/', __FILE__
9
+ TEMPLATE_DIR = File.expand_path 'templates/', RESOURCES_DIR
10
+ ASSETS_DIR = File.expand_path 'assets/', RESOURCES_DIR
11
+
12
+ def self.reporter(format, shell)
13
+ case format
14
+ when 'text'
15
+ shell
16
+ when 'markdown'
17
+ MarkdownReporter.new
18
+ when 'json'
19
+ JSONReporter.new
20
+ when 'yaml'
21
+ YAMLReporter.new
22
+ else
23
+ fail "Unknown report format #{options[:format]}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,4 +1,5 @@
1
1
  require 'hashie/dash'
2
+ require 'hashie/extensions/coercion'
2
3
 
3
4
  module Polytrix
4
5
  class Result < Hashie::Dash
@@ -9,15 +10,15 @@ module Polytrix
9
10
  def_delegators :execution_result, :stdout, :stderr, :exitstatus
10
11
  property :source_file # , required: true
11
12
  property :data
12
- property :validations, default: Validations.new
13
- coerce_key :validations, Validations
13
+ property :validations, default: {}
14
+ coerce_key :validations, Hash[String => Validation]
14
15
 
15
16
  def status
16
17
  # A feature can be validated by different suites, or manually vs an automated suite.
17
18
  # That's why there's a precedence rather than boolean algebra here...
18
- return 'failed' if validations.any? { |v| v.result == 'failed' }
19
- return 'passed' if validations.any? { |v| v.result == 'passed' }
20
- return 'pending' if validations.any? { |v| v.result == 'pending' }
19
+ return 'failed' if validations.values.any? { |v| v.result == 'failed' }
20
+ return 'passed' if validations.values.any? { |v| v.result == 'passed' }
21
+ return 'pending' if validations.values.any? { |v| v.result == 'pending' }
21
22
  'skipped'
22
23
  end
23
24
  end
@@ -0,0 +1,15 @@
1
+ module Polytrix
2
+ module Spies
3
+ class FileSystemSpy < Polytrix::Spy
4
+ def initialize(_app, _server_options)
5
+ end
6
+
7
+ def spy(_challenge)
8
+ end
9
+
10
+ report :summary, SummaryReport
11
+ end
12
+ end
13
+ end
14
+
15
+ Polytrix.configuration.register_spy(Polytrix::Spies::FileSystemSpy)
@@ -0,0 +1,61 @@
1
+ require 'middleware'
2
+
3
+ module Polytrix
4
+ # # @abstract
5
+ class Spy
6
+ def initialize(app, opts = {})
7
+ @app = app
8
+ @opts = opts
9
+ end
10
+
11
+ def call(_challenge)
12
+ fail NotImplementedError, 'Subclass must implement #call'
13
+ end
14
+
15
+ def self.reports
16
+ @reports ||= {}
17
+ end
18
+
19
+ def self.report(type, report_class)
20
+ reports[type] = report_class
21
+ end
22
+ end
23
+
24
+ module Spies
25
+ class << self
26
+ attr_reader :spies
27
+
28
+ def middleware
29
+ @middleware ||= Middleware::Builder.new
30
+ end
31
+
32
+ def spies
33
+ @spies ||= Set.new
34
+ end
35
+
36
+ def register_spy(spy)
37
+ spies.add(spy)
38
+ middleware.insert 0, spy, {}
39
+ end
40
+
41
+ def observe(challenge, &blk)
42
+ middleware = Middleware::Builder.new
43
+ spies.each do |spy|
44
+ middleware.use spy
45
+ end
46
+ middleware.use blk
47
+ middleware.call(challenge)
48
+ end
49
+
50
+ def reports
51
+ # Group by type
52
+ all_reports = spies.flat_map do |spy|
53
+ spy.reports.to_a if spy.respond_to? :reports
54
+ end
55
+ all_reports.each_with_object({}) do |(k, v), h|
56
+ (h[k] ||= []) << v
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -21,7 +21,7 @@ module Polytrix
21
21
  dir = File.dirname(file_name)
22
22
  serialized_string = serialize_hash(Util.stringified_hash(state))
23
23
 
24
- FileUtils.mkdir_p(dir) unless File.directory?(dir)
24
+ FileUtils.mkdir_p(dir)
25
25
  File.open(file_name, 'wb') { |f| f.write(serialized_string) }
26
26
  end
27
27
 
@@ -29,29 +29,10 @@ module Polytrix
29
29
  FileUtils.rm_f(file_name) if File.exist?(file_name)
30
30
  end
31
31
 
32
- def diagnose
33
- raw = read
34
- result = {}
35
- raw.keys.sort.each { |k| result[k] = raw[k] }
36
- result
37
- end
38
-
39
32
  private
40
33
 
41
34
  attr_reader :file_name
42
35
 
43
- # @api private
44
- def read_file
45
- IO.read(file_name)
46
- end
47
-
48
- # @api private
49
- def deserialize_string(string)
50
- SafeYAML.load(string)
51
- rescue SyntaxError, Psych::SyntaxError => ex
52
- raise StateFileLoadError, "Error parsing #{file_name} (#{ex.message})"
53
- end
54
-
55
36
  # @api private
56
37
  def serialize_hash(hash)
57
38
  ::YAML.dump(hash)