linecook 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/History +60 -0
  2. data/License.txt +22 -0
  3. data/README +98 -0
  4. data/bin/linecook +58 -0
  5. data/cookbook +0 -0
  6. data/lib/linecook/attributes.rb +22 -0
  7. data/lib/linecook/commands/command.rb +48 -0
  8. data/lib/linecook/commands/command_error.rb +6 -0
  9. data/lib/linecook/commands/env.rb +23 -0
  10. data/lib/linecook/commands/helper.rb +51 -0
  11. data/lib/linecook/commands/helpers.rb +28 -0
  12. data/lib/linecook/commands/init.rb +82 -0
  13. data/lib/linecook/commands/package.rb +39 -0
  14. data/lib/linecook/commands/vbox.rb +85 -0
  15. data/lib/linecook/commands.rb +6 -0
  16. data/lib/linecook/cookbook.rb +104 -0
  17. data/lib/linecook/helper.rb +117 -0
  18. data/lib/linecook/package.rb +197 -0
  19. data/lib/linecook/recipe.rb +103 -0
  20. data/lib/linecook/shell/posix.rb +145 -0
  21. data/lib/linecook/shell/test.rb +254 -0
  22. data/lib/linecook/shell/unix.rb +117 -0
  23. data/lib/linecook/shell/utils.rb +138 -0
  24. data/lib/linecook/shell.rb +11 -0
  25. data/lib/linecook/template.rb +111 -0
  26. data/lib/linecook/test/file_test.rb +77 -0
  27. data/lib/linecook/test/regexp_escape.rb +86 -0
  28. data/lib/linecook/test.rb +172 -0
  29. data/lib/linecook/utils.rb +53 -0
  30. data/lib/linecook/version.rb +8 -0
  31. data/lib/linecook.rb +6 -0
  32. data/templates/Gemfile +2 -0
  33. data/templates/README +90 -0
  34. data/templates/Rakefile +149 -0
  35. data/templates/_gitignore +5 -0
  36. data/templates/attributes/project_name.rb +4 -0
  37. data/templates/cookbook +9 -0
  38. data/templates/files/file.txt +1 -0
  39. data/templates/helpers/project_name/echo.erb +5 -0
  40. data/templates/project_name.gemspec +30 -0
  41. data/templates/recipes/project_name.rb +20 -0
  42. data/templates/scripts/project_name.yml +7 -0
  43. data/templates/templates/template.txt.erb +3 -0
  44. data/templates/vbox/setup/virtual_box +86 -0
  45. data/templates/vbox/ssh/id_rsa +27 -0
  46. data/templates/vbox/ssh/id_rsa.pub +1 -0
  47. metadata +166 -0
@@ -0,0 +1,254 @@
1
+ require 'linecook/test'
2
+
3
+ module Linecook
4
+ module Shell
5
+ # A module for testing shell scripts.
6
+ #
7
+ # class ShellTestSample < Test::Unit::TestCase
8
+ # include Linecook::Test::Shell
9
+ #
10
+ # # these are the default sh_test options used
11
+ # # in tests like test_sh_command_alias
12
+ # self.sh_test_options = {
13
+ # :cmd_pattern => '% inspect_argv',
14
+ # :cmd => 'ruby -e "puts ARGV.inspect"'
15
+ # }
16
+ #
17
+ # def test_echo
18
+ # assert_equal "goodnight moon", sh("echo goodnight moon").strip
19
+ # end
20
+ #
21
+ # def test_echo_using_sh_test
22
+ # sh_test %q{
23
+ # echo goodnight moon
24
+ # goodnight moon
25
+ # }
26
+ # end
27
+ #
28
+ # def test_sh_command_alias
29
+ # sh_test("% inspect_env") do |output|
30
+ # assert output !~ /NEW_ENV_VAR/
31
+ # end
32
+ #
33
+ # sh_test("NEW_ENV_VAR=blue % inspect_env") do |output|
34
+ # assert output =~ /NEW_ENV_VAR=blue/
35
+ # end
36
+ # end
37
+ # end
38
+ #
39
+ module Test
40
+ include Linecook::Test
41
+
42
+ def setup
43
+ super
44
+ @notify_method_name = true
45
+ end
46
+
47
+ # Sets the specified ENV variables and returns the *current* env.
48
+ # If replace is true, current ENV variables are replaced; otherwise
49
+ # the new env variables are simply added to the existing set.
50
+ def set_env(env={}, replace=false)
51
+ current_env = {}
52
+ ENV.each_pair do |key, value|
53
+ current_env[key] = value
54
+ end
55
+
56
+ ENV.clear if replace
57
+
58
+ env.each_pair do |key, value|
59
+ if value.nil?
60
+ ENV.delete(key)
61
+ else
62
+ ENV[key] = value
63
+ end
64
+ end if env
65
+
66
+ current_env
67
+ end
68
+
69
+ # Sets the specified ENV variables for the duration of the block.
70
+ # If replace is true, current ENV variables are replaced; otherwise
71
+ # the new env variables are simply added to the existing set.
72
+ #
73
+ # Returns the block return.
74
+ def with_env(env={}, replace=false)
75
+ current_env = nil
76
+ begin
77
+ current_env = set_env(env, replace)
78
+ yield
79
+ ensure
80
+ if current_env
81
+ set_env(current_env, true)
82
+ end
83
+ end
84
+ end
85
+
86
+ # Returns true if the ENV variable 'VERBOSE' is true.
87
+ def verbose?
88
+ verbose = ENV['VERBOSE']
89
+ verbose && verbose =~ /^true$/i ? true : false
90
+ end
91
+
92
+ # Returns true if the ENV variable 'QUIET' is true or nil. If 'VERBOSE'
93
+ # and 'QUIET' are both set, verbose wins.
94
+ def quiet?
95
+ return false if verbose?
96
+
97
+ quiet = ENV['QUIET']
98
+ quiet.nil? || quiet =~ /^true$/i ? true : false
99
+ end
100
+
101
+ # Executes the command using IO.popen and returns the stdout content.
102
+ #
103
+ # ==== Note
104
+ # On Windows this method requires the {win32-popen3}[http://rubyforge.org/projects/win32utils]
105
+ # utility. If it is not available, it will have to be installed:
106
+ #
107
+ # % gem install win32-open3
108
+ #
109
+ def sh(cmd, options={})
110
+ if @notify_method_name && !quiet?
111
+ @notify_method_name = false
112
+ puts
113
+ puts method_name
114
+ end
115
+
116
+ original_cmd = cmd
117
+ if cmd_pattern = options[:cmd_pattern]
118
+ cmd = cmd.sub(cmd_pattern, options[:cmd].to_s)
119
+ end
120
+
121
+ start = Time.now
122
+ result = with_env(options[:env], options[:replace_env]) do
123
+ IO.popen(cmd) do |io|
124
+ yield(io) if block_given?
125
+ io.read
126
+ end
127
+ end
128
+
129
+ finish = Time.now
130
+ elapsed = "%.3f" % [finish-start]
131
+ puts " (#{elapsed}s) #{verbose? ? cmd : original_cmd}" unless quiet?
132
+ result
133
+ end
134
+
135
+ # Peforms a shell test. Shell tests execute the command and yield the
136
+ # $stdout result to the block for validation. The command is executed
137
+ # through sh, ie using IO.popen.
138
+ #
139
+ # Options provided to sh_test are merged with the sh_test_options set
140
+ # for the class.
141
+ #
142
+ # ==== Command Aliases
143
+ #
144
+ # The options allow specification of a command pattern that gets
145
+ # replaced with a command alias. Only the first instance of the command
146
+ # pattern is replaced. In addition, shell tests allow the expected result
147
+ # to be specified inline with the command. Used together, these allow
148
+ # multiple tests of a complex command to be specified easily:
149
+ #
150
+ # opts = {
151
+ # :cmd_pattern => '% argv_inspect',
152
+ # :cmd => 'ruby -e "puts ARGV.inspect"'
153
+ # }
154
+ #
155
+ # sh_test %Q{
156
+ # % argv_inspect goodnight moon
157
+ # ["goodnight", "moon"]
158
+ # }, opts
159
+ #
160
+ # sh_test %Q{
161
+ # % argv_inspect hello world
162
+ # ["hello", "world"]
163
+ # }, opts
164
+ #
165
+ # ==== Indents
166
+ #
167
+ # To improve the readability of tests, sh_test will lstrip each line in the
168
+ # expected output to the same degree as the command line. So for instance
169
+ # these all pass:
170
+ #
171
+ # sh_test %Q{
172
+ # % argv_inspect hello world
173
+ # ["hello", "world"]
174
+ # }, opts
175
+ #
176
+ # sh_test %Q{
177
+ # % argv_inspect hello world
178
+ # ["hello", "world"]
179
+ # }, opts
180
+ #
181
+ # sh_test %Q{
182
+ # % argv_inspect hello world
183
+ # ["hello", "world"]
184
+ # }, opts
185
+ #
186
+ # Turn off indent stripping by specifying :indent => false.
187
+ #
188
+ # ==== ENV variables
189
+ #
190
+ # Options may specify a hash of env variables that will be set in the
191
+ # subprocess.
192
+ #
193
+ # sh_test %Q{
194
+ # ruby -e "puts ENV['SAMPLE']"
195
+ # value
196
+ # }, :env => {'SAMPLE' => 'value'}
197
+ #
198
+ # Note it is better to specify env variables in this way rather than
199
+ # through the command trick 'VAR=value cmd ...', as that syntax does
200
+ # not work on Windows. As a point of interest, see
201
+ # http://gist.github.com/107363 for a demonstration of ENV
202
+ # variables being inherited by subprocesses.
203
+ #
204
+ def sh_test(cmd, options={})
205
+ options = sh_test_options.merge(options)
206
+
207
+ # strip indentiation if possible
208
+ if cmd =~ /\A(?:\s*?\n)?( *)(.*?\n)(.*)\z/m
209
+ indent, cmd, expected = $1, $2, $3
210
+ cmd.strip!
211
+
212
+ if indent.length > 0 && options[:indents]
213
+ expected.gsub!(/^ {0,#{indent.length}}/, '')
214
+ end
215
+ end
216
+
217
+ result = sh(cmd, options)
218
+
219
+ assert_equal(expected, result, cmd) if expected
220
+ yield(result) if block_given?
221
+ result
222
+ end
223
+
224
+ # Similar to sh_test, but matches the output against each of the
225
+ # regexps. A hash of sh options can be provided as the last argument;
226
+ # it will be merged with the default sh_test_options.
227
+ #
228
+ # The output is yielded to the block, if given, for further validation.
229
+ # Returns the sh output.
230
+ def sh_match(cmd, *regexps)
231
+ options = regexps.last.kind_of?(Hash) ? regexps.pop : {}
232
+ options = sh_test_options.merge(options)
233
+ result = sh(cmd, options)
234
+
235
+ regexps.each do |regexp|
236
+ assert_match regexp, result, cmd
237
+ end
238
+ yield(result) if block_given?
239
+ result
240
+ end
241
+
242
+ # Returns a hash of default sh_test options.
243
+ def sh_test_options
244
+ {
245
+ :cmd_pattern => '% ',
246
+ :cmd => '2>&1 ',
247
+ :indents => true,
248
+ :env => {},
249
+ :replace_env => false
250
+ }
251
+ end
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,117 @@
1
+ require 'erb'
2
+
3
+ # Generated by Linecook, do not edit.
4
+ module Linecook
5
+ module Shell
6
+ module Unix
7
+ require 'linecook/shell/posix'
8
+ include Posix
9
+ # :stopdoc:
10
+ CAT_LINE = __LINE__ + 2
11
+ CAT = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
12
+ cat<% sources.each do |source| %> "<%= source %>"<% end %>
13
+ END_OF_TEMPLATE
14
+ # :startdoc:
15
+
16
+ def cat(*sources)
17
+ eval(CAT, binding, __FILE__, CAT_LINE)
18
+ nil
19
+ end
20
+
21
+ def _cat(*args, &block) # :nodoc:
22
+ capture { cat(*args, &block) }
23
+ end
24
+
25
+ # :stopdoc:
26
+ CHMOD_LINE = __LINE__ + 2
27
+ CHMOD = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
28
+ <% if mode %>
29
+ chmod <%= mode %> "<%= target %>"
30
+ <% check_status %>
31
+ <% end %>
32
+ END_OF_TEMPLATE
33
+ # :startdoc:
34
+
35
+ def chmod(target, mode=nil)
36
+ eval(CHMOD, binding, __FILE__, CHMOD_LINE)
37
+ nil
38
+ end
39
+
40
+ def _chmod(*args, &block) # :nodoc:
41
+ capture { chmod(*args, &block) }
42
+ end
43
+
44
+ # :stopdoc:
45
+ CHOWN_LINE = __LINE__ + 2
46
+ CHOWN = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
47
+ <% if user || group %>
48
+ chown <%= user %>:<%= group %> "<%= target %>"
49
+ <% check_status %>
50
+ <% end %>
51
+ END_OF_TEMPLATE
52
+ # :startdoc:
53
+
54
+ def chown(target, user=nil, group=nil)
55
+ eval(CHOWN, binding, __FILE__, CHOWN_LINE)
56
+ nil
57
+ end
58
+
59
+ def _chown(*args, &block) # :nodoc:
60
+ capture { chown(*args, &block) }
61
+ end
62
+
63
+ # :stopdoc:
64
+ ECHO_LINE = __LINE__ + 2
65
+ ECHO = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
66
+ echo '<%= args.join(" ") %>'
67
+ END_OF_TEMPLATE
68
+ # :startdoc:
69
+
70
+ # Echos input
71
+ def echo(*args)
72
+ eval(ECHO, binding, __FILE__, ECHO_LINE)
73
+ nil
74
+ end
75
+
76
+ def _echo(*args, &block) # :nodoc:
77
+ capture { echo(*args, &block) }
78
+ end
79
+
80
+ # :stopdoc:
81
+ LN_S_LINE = __LINE__ + 2
82
+ LN_S = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
83
+ ln -sf "<%= source %>" "<%= target %>"
84
+ <% check_status %>
85
+
86
+ END_OF_TEMPLATE
87
+ # :startdoc:
88
+
89
+ def ln_s(source, target)
90
+ eval(LN_S, binding, __FILE__, LN_S_LINE)
91
+ nil
92
+ end
93
+
94
+ def _ln_s(*args, &block) # :nodoc:
95
+ capture { ln_s(*args, &block) }
96
+ end
97
+
98
+ # :stopdoc:
99
+ RM_LINE = __LINE__ + 2
100
+ RM = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
101
+ <% only_if %Q{ls -l "#{path}"} do %>
102
+ rm <% if opts %><%= opts %> <% end %>"<%= path %>"
103
+ <% end %>
104
+ END_OF_TEMPLATE
105
+ # :startdoc:
106
+
107
+ def rm(path, opts=nil)
108
+ eval(RM, binding, __FILE__, RM_LINE)
109
+ nil
110
+ end
111
+
112
+ def _rm(*args, &block) # :nodoc:
113
+ capture { rm(*args, &block) }
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,138 @@
1
+ require 'erb'
2
+
3
+ # Generated by Linecook, do not edit.
4
+ module Linecook
5
+ module Shell
6
+ module Utils
7
+ require 'linecook/shell/posix'
8
+ include Posix
9
+
10
+ DEFAULT_SHELL_PATH = '/bin/sh'
11
+ DEFAULT_ENV_PATH = '/usr/bin/env'
12
+
13
+ TARGET_PATH = '$LINECOOK_DIR/%s'
14
+
15
+ attr_writer :shell_path
16
+ attr_writer :env_path
17
+
18
+ def shell_path
19
+ @shell_path ||= DEFAULT_SHELL_PATH
20
+ end
21
+
22
+ def env_path
23
+ @env_path ||= DEFAULT_ENV_PATH
24
+ end
25
+
26
+ def target_path(source_path)
27
+ TARGET_PATH % super(source_path)
28
+ end
29
+
30
+ def close
31
+ unless closed?
32
+ break_line " (#{target_name}) "
33
+ end
34
+
35
+ super
36
+ end
37
+ # :stopdoc:
38
+ BREAK_LINE_LINE = __LINE__ + 2
39
+ BREAK_LINE = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
40
+ <% n = (76 - comment.length)/2 %>
41
+ <%= "#" * n %><%= comment %><%= "#" * n %>
42
+
43
+ END_OF_TEMPLATE
44
+ # :startdoc:
45
+
46
+ def break_line(comment="")
47
+ eval(BREAK_LINE, binding, __FILE__, BREAK_LINE_LINE)
48
+ nil
49
+ end
50
+
51
+ def _break_line(*args, &block) # :nodoc:
52
+ capture { break_line(*args, &block) }
53
+ end
54
+
55
+ # :stopdoc:
56
+ CHECK_STATUS_LINE = __LINE__ + 2
57
+ CHECK_STATUS = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
58
+ check_status <%= status %> $? $LINENO
59
+ END_OF_TEMPLATE
60
+ # :startdoc:
61
+
62
+ # Adds a check after a command that ensures the status is as indicated
63
+ def check_status(status=0)
64
+ eval(CHECK_STATUS, binding, __FILE__, CHECK_STATUS_LINE)
65
+ nil
66
+ end
67
+
68
+ def _check_status(*args, &block) # :nodoc:
69
+ capture { check_status(*args, &block) }
70
+ end
71
+
72
+ # :stopdoc:
73
+ CHECK_STATUS_FUNCTION_LINE = __LINE__ + 2
74
+ CHECK_STATUS_FUNCTION = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
75
+ function check_status { if [ $1 -ne $2 ]; then echo "[$2] $0:$3"; exit $2; fi }
76
+ END_OF_TEMPLATE
77
+ # :startdoc:
78
+
79
+ # Adds the check status function.
80
+ def check_status_function
81
+ eval(CHECK_STATUS_FUNCTION, binding, __FILE__, CHECK_STATUS_FUNCTION_LINE)
82
+ nil
83
+ end
84
+
85
+ def _check_status_function(*args, &block) # :nodoc:
86
+ capture { check_status_function(*args, &block) }
87
+ end
88
+
89
+ # :stopdoc:
90
+ SHEBANG_LINE = __LINE__ + 2
91
+ SHEBANG = "self." + ERB.new(<<'END_OF_TEMPLATE', nil, '<>').src
92
+ #! <%= shell_path %>
93
+
94
+ <%= break_line %>
95
+ <%= check_status_function %>
96
+
97
+ export -f check_status
98
+ export LINECOOK_DIR=$(dirname $0)
99
+ export LINECOOK_OPTIONS=
100
+
101
+ while getopts bhvx opt
102
+ do
103
+ case $opt in
104
+ v) LINECOOK_OPTIONS="$LINECOOK_OPTIONS -v";;
105
+ x) LINECOOK_OPTIONS="$LINECOOK_OPTIONS -x";;
106
+ h) printf "Usage: %s: [-hvx]\n" $0
107
+ printf " -h prints this help\n"
108
+ printf " -v verbose (set -v)\n"
109
+ printf " -x xtrace (set -x)\n"
110
+ exit 0;;
111
+ ?) printf "Usage: %s: [-hvx]\n" $0
112
+ exit 2;;
113
+ esac
114
+ done
115
+
116
+ set $LINECOOK_OPTIONS > /dev/null
117
+ <%= break_line " #{target_name} " %>
118
+
119
+ END_OF_TEMPLATE
120
+ # :startdoc:
121
+
122
+ # == Notes
123
+
124
+ # Use dev/null on set such that no options will not dump ENV into stdout.
125
+
126
+ def shebang(shell_path=DEFAULT_SHELL_PATH, env_path=DEFAULT_ENV_PATH)
127
+ @shell_path = shell_path
128
+ @env_path = env_path
129
+ eval(SHEBANG, binding, __FILE__, SHEBANG_LINE)
130
+ nil
131
+ end
132
+
133
+ def _shebang(*args, &block) # :nodoc:
134
+ capture { shebang(*args, &block) }
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,11 @@
1
+ require 'linecook/shell/posix'
2
+ require 'linecook/shell/unix'
3
+ require 'linecook/shell/utils'
4
+
5
+ module Linecook
6
+ module Shell
7
+ include Posix
8
+ include Unix
9
+ include Utils
10
+ end
11
+ end
@@ -0,0 +1,111 @@
1
+ require 'ostruct'
2
+ require 'stringio'
3
+ require 'erb'
4
+
5
+ module Linecook
6
+ class Template
7
+ class << self
8
+ def build(template, locals, template_path=nil)
9
+ ERB.new(template).result(OpenStruct.new(locals).send(:binding))
10
+ end
11
+ end
12
+
13
+ attr_reader :erbout
14
+
15
+ def initialize
16
+ @erbout = StringIO.new
17
+ end
18
+
19
+ # Returns self (not the underlying erbout storage that actually receives
20
+ # the output lines). In the ERB context, this method directs erb outputs
21
+ # to Template#concat and into the redirect mechanism.
22
+ def _erbout
23
+ self
24
+ end
25
+
26
+ # Sets the underlying erbout storage to input.
27
+ def _erbout=(input)
28
+ end
29
+
30
+ # Concatenates the specified input to the underlying erbout storage.
31
+ def concat(input)
32
+ erbout << input
33
+ self
34
+ end
35
+
36
+ def capture(strip=true)
37
+ current, redirect = erbout, StringIO.new
38
+
39
+ begin
40
+ @erbout = redirect
41
+ yield
42
+ ensure
43
+ @erbout = current
44
+ end
45
+
46
+ str = redirect.string
47
+ str.strip! if strip
48
+ str
49
+ end
50
+
51
+ def indent(indent=' ', &block)
52
+ capture(&block).split("\n").each do |line|
53
+ concat "#{indent}#{line}\n"
54
+ end
55
+ self
56
+ end
57
+
58
+ def nest(*nestings)
59
+ options = nestings.last.kind_of?(Hash) ? nestings.pop : {}
60
+ indent = options[:indent] || " "
61
+ line_sep = options[:line_sep] || "\n"
62
+
63
+ content = capture { yield }
64
+ return content if nestings.empty?
65
+
66
+ depth = nestings.length
67
+ lines = [indent * depth + content.gsub(/#{line_sep}/, line_sep + indent * depth)]
68
+
69
+ nestings.reverse_each do |(start_line, end_line)|
70
+ depth -= 1
71
+ lines.unshift(indent * depth + start_line)
72
+ lines << (indent * depth + end_line)
73
+ end
74
+
75
+ concat lines.join(line_sep)
76
+ end
77
+
78
+ def rstrip(n=10)
79
+ yield if block_given?
80
+
81
+ pos = erbout.pos
82
+ n = pos if pos < n
83
+ start = pos - n
84
+
85
+ erbout.pos = start
86
+ tail = erbout.read(n).rstrip
87
+
88
+ erbout.pos = start
89
+ erbout.truncate start
90
+
91
+ tail.length == 0 && start > 0 ? rstrip(n * 2) : concat(tail)
92
+ end
93
+
94
+ def close
95
+ erbout.close unless closed?
96
+ self
97
+ end
98
+
99
+ def closed?
100
+ erbout.closed?
101
+ end
102
+
103
+ def result(&block)
104
+ instance_eval(&block) if block
105
+
106
+ erbout.flush
107
+ erbout.rewind
108
+ erbout.read
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,77 @@
1
+ module Linecook
2
+ module Test
3
+ module FileTest
4
+ module ClassMethods
5
+ attr_accessor :class_dir
6
+
7
+ def self.extended(base)
8
+ # Infers the test directory from the calling file.
9
+ # 'some_class_test.rb' => 'some_class_test'
10
+ calling_file = caller[2].gsub(/:\d+(:in .*)?$/, "")
11
+ base.class_dir = calling_file.chomp(File.extname(calling_file))
12
+ end
13
+ end
14
+
15
+ module ModuleMethods
16
+ module_function
17
+
18
+ def included(base)
19
+ base.extend base.kind_of?(Class) ? ClassMethods : ModuleMethods
20
+ super
21
+ end
22
+ end
23
+
24
+ extend ModuleMethods
25
+
26
+ attr_reader :user_dir
27
+ attr_reader :method_dir
28
+
29
+ def setup
30
+ super
31
+ @user_dir = Dir.pwd
32
+ @method_dir = File.expand_path(method_name, self.class.class_dir)
33
+
34
+ cleanup method_dir
35
+ FileUtils.mkdir_p method_dir
36
+ Dir.chdir method_dir
37
+ end
38
+
39
+ def teardown
40
+ Dir.chdir user_dir
41
+
42
+ unless ENV["KEEP_OUTPUTS"] == "true"
43
+ cleanup class_dir
44
+ end
45
+
46
+ super
47
+ end
48
+
49
+ def cleanup(dir)
50
+ FileUtils.rm_r(dir) if File.exists?(dir)
51
+ end
52
+
53
+ def path(relative_path)
54
+ File.expand_path(relative_path, method_dir)
55
+ end
56
+
57
+ def prepare(relative_path)
58
+ target = path(relative_path)
59
+
60
+ target_dir = File.dirname(target)
61
+ FileUtils.mkdir_p(target_dir) unless File.exists?(target_dir)
62
+
63
+ target
64
+ end
65
+
66
+ def file(relative_path, &block)
67
+ target = prepare(relative_path)
68
+ block ? File.open(target, 'w', &block) : FileUtils.touch(target)
69
+ target
70
+ end
71
+
72
+ def class_dir
73
+ self.class.class_dir
74
+ end
75
+ end
76
+ end
77
+ end