linecook 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History +60 -0
- data/License.txt +22 -0
- data/README +98 -0
- data/bin/linecook +58 -0
- data/cookbook +0 -0
- data/lib/linecook/attributes.rb +22 -0
- data/lib/linecook/commands/command.rb +48 -0
- data/lib/linecook/commands/command_error.rb +6 -0
- data/lib/linecook/commands/env.rb +23 -0
- data/lib/linecook/commands/helper.rb +51 -0
- data/lib/linecook/commands/helpers.rb +28 -0
- data/lib/linecook/commands/init.rb +82 -0
- data/lib/linecook/commands/package.rb +39 -0
- data/lib/linecook/commands/vbox.rb +85 -0
- data/lib/linecook/commands.rb +6 -0
- data/lib/linecook/cookbook.rb +104 -0
- data/lib/linecook/helper.rb +117 -0
- data/lib/linecook/package.rb +197 -0
- data/lib/linecook/recipe.rb +103 -0
- data/lib/linecook/shell/posix.rb +145 -0
- data/lib/linecook/shell/test.rb +254 -0
- data/lib/linecook/shell/unix.rb +117 -0
- data/lib/linecook/shell/utils.rb +138 -0
- data/lib/linecook/shell.rb +11 -0
- data/lib/linecook/template.rb +111 -0
- data/lib/linecook/test/file_test.rb +77 -0
- data/lib/linecook/test/regexp_escape.rb +86 -0
- data/lib/linecook/test.rb +172 -0
- data/lib/linecook/utils.rb +53 -0
- data/lib/linecook/version.rb +8 -0
- data/lib/linecook.rb +6 -0
- data/templates/Gemfile +2 -0
- data/templates/README +90 -0
- data/templates/Rakefile +149 -0
- data/templates/_gitignore +5 -0
- data/templates/attributes/project_name.rb +4 -0
- data/templates/cookbook +9 -0
- data/templates/files/file.txt +1 -0
- data/templates/helpers/project_name/echo.erb +5 -0
- data/templates/project_name.gemspec +30 -0
- data/templates/recipes/project_name.rb +20 -0
- data/templates/scripts/project_name.yml +7 -0
- data/templates/templates/template.txt.erb +3 -0
- data/templates/vbox/setup/virtual_box +86 -0
- data/templates/vbox/ssh/id_rsa +27 -0
- data/templates/vbox/ssh/id_rsa.pub +1 -0
- 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,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
|