falsework 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2010 <%= @gecos %>.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,57 @@
1
+ =Name
2
+
3
+ <%= @project %>--an util to put function in yo function so yo can return
4
+ while yo return.
5
+
6
+
7
+ ==Synopsis
8
+
9
+ <%= @project %> [options]
10
+
11
+
12
+ ==Description
13
+
14
+ The <%= @project %> utility does something.
15
+
16
+ The options are as follows:
17
+
18
+ --config-dirs:: List all possible locations for the
19
+ configuration file. The first found wins.
20
+
21
+ --config NAME:: The name of the configuration file. If
22
+ it contains <tt>/</tt> in it, the list from
23
+ <tt>--config-dirs</tt> is ignored.
24
+
25
+ -V:: Show falsework version and exit.
26
+
27
+ -v:: Be more verbose. You can supply it several
28
+ times, viz. <tt>-vv</tt> dumps even more
29
+ debug info.
30
+
31
+ --foobar NAME Huh?
32
+
33
+ ==Configuration
34
+
35
+ <%= @project %> looks for its configuration at 3 places at start up.
36
+
37
+ 1. At <tt><%= @project.upcase %>_CONF</tt> env variable.
38
+ (Its format is exactly similar to CL options.)
39
+
40
+ 2. At the configuration file. Its default name is
41
+ <tt><%= @project %>.yaml</tt> and it can be stored in several
42
+ system directories which are observable by <tt>--config--dirs</tt> CL
43
+ option.
44
+
45
+ 3. At command line.
46
+
47
+ Higher number levels overrides the values from lower number levels.
48
+
49
+ The configuration file must be in YAML format. Look into <tt>`gem env
50
+ gemdir`/gems/<%= @project %>-x.y.z/etc/</tt> directory for samples.
51
+
52
+
53
+ ==Examples
54
+
55
+ % ri <%= @project.capitalize %>
56
+ % <%= @project %> --config-dirs
57
+ % <%= @project %> -V
@@ -0,0 +1,2 @@
1
+ ---
2
+ :foobar: foobar
@@ -0,0 +1,6 @@
1
+ module <%= @project.capitalize %>
2
+ module Meta
3
+ NAME = '<%= @project %>'
4
+ VERSION = '0.0.1'
5
+ end
6
+ end
@@ -0,0 +1,203 @@
1
+ # :erb:
2
+ require 'yaml'
3
+ require 'shellwords.rb'
4
+ require 'optparse'
5
+ require 'pp'
6
+
7
+ require_relative 'meta'
8
+
9
+ # :include: ../../README.rdoc
10
+ module <%= @project.capitalize %>
11
+
12
+ class Utils
13
+ # Return a directory with program libraries.
14
+ def self.gem_libdir
15
+ t = ["#{File.dirname(File.expand_path($0))}/../lib/#{<%= @project.capitalize %>::Meta::NAME}",
16
+ "#{Gem.dir}/gems/#{<%= @project.capitalize %>::Meta::NAME}-#{<%= @project.capitalize %>::Meta::VERSION}/lib/#{<%= @project.capitalize %>::Meta::NAME}",
17
+ "lib/#{<%= @project.capitalize %>::Meta::NAME}"]
18
+ t.each {|i| return i if File.readable?(i) }
19
+ fail "all paths are invalid: #{t}"
20
+ end
21
+
22
+ # Analogue to shell command +which+.
23
+ def self.in_path?(file)
24
+ return true if file =~ %r%\A/% and File.exist? file
25
+
26
+ ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path|
27
+ File.exist? File.join(path, file)
28
+ end
29
+ end
30
+
31
+ # Print an error message _t_ and exit if _ec_ > 0.
32
+ def self.errx(ec, t)
33
+ STDERR.puts File.basename($0) + ' error: ' + t.to_s
34
+ exit ec if ec > 0
35
+ end
36
+
37
+ # Print a warning.
38
+ def self.warnx(t)
39
+ STDERR.puts File.basename($0) + ' warning: ' + t.to_s
40
+ end
41
+
42
+ # #veputs uses this to decide to put a newline or not to put.
43
+ NNL_MARK = '__NNL__'
44
+
45
+ # Use this in your CL options to check if modifying some variable is
46
+ # not an idempotent act.
47
+ attr_reader :cl_opt_protect
48
+
49
+ # [conf] Typically must be a reference to some global variable.
50
+ def initialize(conf)
51
+ @conf = conf
52
+ @conf[:verbose] = 0
53
+ @conf[:banner] = "Usage: #{File.basename($0)} [options]"
54
+ @conf[:config] = Meta::NAME + '.yaml'
55
+ @conf[:config_dirs] = [ENV['HOME']+'/.'+Meta::NAME,
56
+ File.absolute_path("#{File.dirname(File.expand_path($0))}/../etc"),
57
+ '/usr/etc', '/usr/local/etc', '/etc',
58
+ "#{Gem.dir}/gems/#{Meta::NAME}-#{Meta::VERSION}/etc"
59
+ ]
60
+ @conf[:config_env] = [Meta::NAME.upcase + '_CONF']
61
+
62
+ @cl_parsing_times = 0 # not used
63
+ @cl_opt_protect = false
64
+ end
65
+
66
+ # [level] A verbose level.
67
+ # [t] A string to print.
68
+ #
69
+ # Don't print _t_ with a newline if it contains NNL_MARK at the end.
70
+ def veputs(level, t)
71
+ t = t.dup
72
+ nnl = nil
73
+ if t.match(/#{NNL_MARK}$/)
74
+ t.sub!(/#{$&}/, '')
75
+ nnl = 1
76
+ end
77
+
78
+ if @conf[:verbose] >= level
79
+ nnl ? print(t) : puts(t)
80
+ STDOUT.flush
81
+ end
82
+ end
83
+
84
+ # Run all configuration parsing in a batch.
85
+ #
86
+ # [rvars] A list of variable names which must be in the
87
+ # configuration file.
88
+ #
89
+ # If no block is given, only standard CL options will be analysed.
90
+ def config_parse(rvars, &block)
91
+ cb = ->(b, src) {
92
+ if b
93
+ block.call src
94
+ else
95
+ # very basic default options
96
+ cl_parse(src, nil, true)
97
+ end
98
+ }
99
+
100
+ # 1. parse env
101
+ @conf[:config_env].each {|i|
102
+ # puts '0 run:'
103
+ cb.call(block_given?, ENV[i].shellsplit) if ENV.key?(i)
104
+ }
105
+
106
+ # 2. parse CL in case of '--config' option
107
+ # puts "\n1 run"
108
+ @cl_opt_protect = true
109
+ cb.call(block_given?, ARGV.dup)
110
+ @cl_opt_protect = false
111
+
112
+ # 3. load the configuration file & do the final CL parsing
113
+ begin
114
+ # puts "\n2 run"
115
+ r = config_flat_load(rvars)
116
+ rescue
117
+ Utils.errx(1, "cannot load config: #{$!}")
118
+ end
119
+ veputs(1, "Loaded config: #{r}")
120
+ cb.call(block_given?, ARGV)
121
+ end
122
+
123
+ # Load a config file immediately if it contains '/' in its name,
124
+ # otherwise search through several dirs for it.
125
+ #
126
+ # [rvars] a list of requied variables in the config
127
+ #
128
+ # Return a loaded filename or nil on error.
129
+ def config_flat_load(rvars)
130
+ p = ->(f) {
131
+ if File.readable?(f)
132
+ begin
133
+ myconf = YAML.load_file(f)
134
+ rescue
135
+ abort("cannot parse #{f}: #{$!}")
136
+ end
137
+ rvars.each { |i|
138
+ fail "missing or nil '#{i}' in #{f}" if ! myconf.key?(i.to_sym) || ! myconf[i.to_sym]
139
+ }
140
+ @conf.merge!(myconf)
141
+ return @conf[:config]
142
+ end
143
+ return nil
144
+ }
145
+
146
+ if @conf[:config].index('/')
147
+ return p.call(@config[:config])
148
+ else
149
+ @conf[:config_dirs].each {|dir|
150
+ return dir+'/'+@conf[:config] if p.call(dir + '/' + @conf[:config])
151
+ }
152
+ end
153
+
154
+ return nil
155
+ end
156
+
157
+
158
+ # Parses CL-like options.
159
+ #
160
+ # [src] An array of options (usually +ARGV+).
161
+ #
162
+ # If _o_ is non nil function parses _src_ immediately, otherwise it
163
+ # only creates +OptionParser+ object and return it (if _simple_ is
164
+ # false).
165
+ def cl_parse(src, o = nil, simple = false)
166
+ if ! o then
167
+ # puts "NEW o (#{cl_opt_protect})" + src.to_s
168
+ o = OptionParser.new
169
+ o.banner = @conf[:banner]
170
+ o.on('-v', 'Be more verbose.') { |i|
171
+ # puts "cl_parsing_times "+cl_parsing_times.to_s
172
+ @conf[:verbose] += 1 unless cl_opt_protect
173
+ }
174
+ o.on('-V', 'Show version & exit.') { |i|
175
+ puts Meta::VERSION
176
+ exit 0
177
+ }
178
+ o.on('--config NAME', "Set a config name (default is #{@conf[:config]})") {|i|
179
+ @conf[:config] = i
180
+ }
181
+ o.on('--config-dirs', 'Show possible config locations') {
182
+ @conf[:config_dirs].each { |j|
183
+ f = j + '/' + @conf[:config]
184
+ puts (File.readable?(f) ? '* ' : ' ') + f
185
+ }
186
+ exit 0
187
+ }
188
+
189
+ return o if ! simple
190
+ end
191
+
192
+ begin
193
+ o.parse!(src)
194
+ @cl_parsing_times += 1
195
+ rescue
196
+ Utils.errx(1, $!.to_s)
197
+ end
198
+ end
199
+
200
+ end # Utils
201
+ end
202
+
203
+ # Don't remove this: 2010-12-22T01:03:15+02:00 falsework 0.0.1
@@ -0,0 +1,48 @@
1
+ # :erb:
2
+ # Various staff for minitest.
3
+
4
+ require 'fileutils'
5
+ require 'open4'
6
+
7
+ include FileUtils
8
+
9
+ require_relative '../lib/<%= @project %>/utils'
10
+ include <%= @project.capitalize %>
11
+
12
+ # don't run tests automatically if they were invoked as 'gem check -t ...'
13
+ if $0 =~ /gem/
14
+ require 'minitest/unit'
15
+ else
16
+ require 'minitest/autorun'
17
+ end
18
+
19
+ def cmd_run(cmd)
20
+ so = sr = ''
21
+ status = Open4::popen4(cmd) { |pid, stdin, stdout, stderr|
22
+ so = stdout.read
23
+ sr = stderr.read
24
+ }
25
+ [status.exitstatus, sr, so]
26
+ end
27
+
28
+ # Return the right directory for (probably executable) _c_.
29
+ def cmd(c)
30
+ case File.basename(Dir.pwd)
31
+ when Meta::NAME.downcase
32
+ # test probably is executed from the Rakefile
33
+ Dir.chdir('test')
34
+ when 'test'
35
+ # we are in the test directory, there is nothing special to do
36
+ else
37
+ # tests were invoked by 'gem check -t <%= @project %>'
38
+ begin
39
+ Dir.chdir(Utils.gem_libdir + '/../../test')
40
+ rescue
41
+ raise "running tests from '#{Dir.pwd}' isn't supported: #{$!}"
42
+ end
43
+ end
44
+
45
+ '../bin/' + c
46
+ end
47
+
48
+ # Don't remove this: 2010-12-22T01:03:15+02:00 falsework 0.0.1
@@ -0,0 +1,13 @@
1
+ require_relative 'helper'
2
+
3
+ class Test<%= @project.capitalize %>_<%= rand 2**32 %> < MiniTest::Unit::TestCase
4
+ CMD = cmd('<%= @project %>') # get path to the exe & cd to tests directory
5
+
6
+ def setup
7
+ # this runs every time before test_*
8
+ end
9
+
10
+ def test_foobar
11
+ fail "\u0430\u0439\u043D\u044D\u043D\u044D".encode(Encoding.default_external, 'UTF-8')
12
+ end
13
+ end
@@ -0,0 +1,201 @@
1
+ # :erb:
2
+ require 'yaml'
3
+ require 'shellwords.rb'
4
+ require 'optparse'
5
+ require 'pp'
6
+
7
+ require_relative 'meta'
8
+
9
+ # :include: ../../README.rdoc
10
+ module Falsework
11
+
12
+ class Utils
13
+ # Return a directory with program libraries.
14
+ def self.gem_libdir
15
+ t = ["#{File.dirname(File.expand_path($0))}/../lib/#{Falsework::Meta::NAME}",
16
+ "#{Gem.dir}/gems/#{Falsework::Meta::NAME}-#{Falsework::Meta::VERSION}/lib/#{Falsework::Meta::NAME}",
17
+ "lib/#{Falsework::Meta::NAME}"]
18
+ t.each {|i| return i if File.readable?(i) }
19
+ fail "all paths are invalid: #{t}"
20
+ end
21
+
22
+ # Analogue to shell command +which+.
23
+ def self.in_path?(file)
24
+ return true if file =~ %r%\A/% and File.exist? file
25
+
26
+ ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path|
27
+ File.exist? File.join(path, file)
28
+ end
29
+ end
30
+
31
+ # Print an error message _t_ and exit if _ec_ > 0.
32
+ def self.errx(ec, t)
33
+ STDERR.puts File.basename($0) + ' error: ' + t.to_s
34
+ exit ec if ec > 0
35
+ end
36
+
37
+ # Print a warning.
38
+ def self.warnx(t)
39
+ STDERR.puts File.basename($0) + ' warning: ' + t.to_s
40
+ end
41
+
42
+ # #veputs uses this to decide to put a newline or not to put.
43
+ NNL_MARK = '__NNL__'
44
+
45
+ # Use this in your CL options to check if modifying some variable is
46
+ # not an idempotent act.
47
+ attr_reader :cl_opt_protect
48
+
49
+ # [conf] Typically must be a reference to some global variable.
50
+ def initialize(conf)
51
+ @conf = conf
52
+ @conf[:verbose] = 0
53
+ @conf[:banner] = "Usage: #{File.basename($0)} [options]"
54
+ @conf[:config] = Meta::NAME + '.yaml'
55
+ @conf[:config_dirs] = [ENV['HOME']+'/.'+Meta::NAME,
56
+ File.absolute_path("#{File.dirname(File.expand_path($0))}/../etc"),
57
+ '/usr/etc', '/usr/local/etc', '/etc',
58
+ "#{Gem.dir}/gems/#{Meta::NAME}-#{Meta::VERSION}/etc"
59
+ ]
60
+ @conf[:config_env] = [Meta::NAME.upcase + '_CONF']
61
+
62
+ @cl_parsing_times = 0 # not used
63
+ @cl_opt_protect = false
64
+ end
65
+
66
+ # [level] A verbose level.
67
+ # [t] A string to print.
68
+ #
69
+ # Don't print _t_ with a newline if it contains NNL_MARK at the end.
70
+ def veputs(level, t)
71
+ t = t.dup
72
+ nnl = nil
73
+ if t.match(/#{NNL_MARK}$/)
74
+ t.sub!(/#{$&}/, '')
75
+ nnl = 1
76
+ end
77
+
78
+ if @conf[:verbose] >= level
79
+ nnl ? print(t) : puts(t)
80
+ STDOUT.flush
81
+ end
82
+ end
83
+
84
+ # Run all configuration parsing in a batch.
85
+ #
86
+ # [rvars] A list of variable names which must be in the
87
+ # configuration file.
88
+ #
89
+ # If no block is given, only standard CL options will be analysed.
90
+ def config_parse(rvars, &block)
91
+ cb = ->(b, src) {
92
+ if b
93
+ block.call src
94
+ else
95
+ # very basic default options
96
+ cl_parse(src, nil, true)
97
+ end
98
+ }
99
+
100
+ # 1. parse env
101
+ @conf[:config_env].each {|i|
102
+ # puts '0 run:'
103
+ cb.call(block_given?, ENV[i].shellsplit) if ENV.key?(i)
104
+ }
105
+
106
+ # 2. parse CL in case of '--config' option
107
+ # puts "\n1 run"
108
+ @cl_opt_protect = true
109
+ cb.call(block_given?, ARGV.dup)
110
+ @cl_opt_protect = false
111
+
112
+ # 3. load the configuration file & do the final CL parsing
113
+ begin
114
+ # puts "\n2 run"
115
+ r = config_flat_load(rvars)
116
+ rescue
117
+ Utils.errx(1, "cannot load config: #{$!}")
118
+ end
119
+ veputs(1, "Loaded config: #{r}")
120
+ cb.call(block_given?, ARGV)
121
+ end
122
+
123
+ # Load a config file immediately if it contains '/' in its name,
124
+ # otherwise search through several dirs for it.
125
+ #
126
+ # [rvars] a list of requied variables in the config
127
+ #
128
+ # Return a loaded filename or nil on error.
129
+ def config_flat_load(rvars)
130
+ p = ->(f) {
131
+ if File.readable?(f)
132
+ begin
133
+ myconf = YAML.load_file(f)
134
+ rescue
135
+ abort("cannot parse #{f}: #{$!}")
136
+ end
137
+ rvars.each { |i|
138
+ fail "missing or nil '#{i}' in #{f}" if ! myconf.key?(i.to_sym) || ! myconf[i.to_sym]
139
+ }
140
+ @conf.merge!(myconf)
141
+ return @conf[:config]
142
+ end
143
+ return nil
144
+ }
145
+
146
+ if @conf[:config].index('/')
147
+ return p.call(@config[:config])
148
+ else
149
+ @conf[:config_dirs].each {|dir|
150
+ return dir+'/'+@conf[:config] if p.call(dir + '/' + @conf[:config])
151
+ }
152
+ end
153
+
154
+ return nil
155
+ end
156
+
157
+
158
+ # Parses CL-like options.
159
+ #
160
+ # [src] An array of options (usually +ARGV+).
161
+ #
162
+ # If _o_ is non nil function parses _src_ immediately, otherwise it
163
+ # only creates +OptionParser+ object and return it (if _simple_ is
164
+ # false).
165
+ def cl_parse(src, o = nil, simple = false)
166
+ if ! o then
167
+ # puts "NEW o (#{cl_opt_protect})" + src.to_s
168
+ o = OptionParser.new
169
+ o.banner = @conf[:banner]
170
+ o.on('-v', 'Be more verbose.') { |i|
171
+ # puts "cl_parsing_times "+cl_parsing_times.to_s
172
+ @conf[:verbose] += 1 unless cl_opt_protect
173
+ }
174
+ o.on('-V', 'Show version & exit.') { |i|
175
+ puts Meta::VERSION
176
+ exit 0
177
+ }
178
+ o.on('--config NAME', "Set a config name (default is #{@conf[:config]})") {|i|
179
+ @conf[:config] = i
180
+ }
181
+ o.on('--config-dirs', 'Show possible config locations') {
182
+ @conf[:config_dirs].each { |j|
183
+ f = j + '/' + @conf[:config]
184
+ puts (File.readable?(f) ? '* ' : ' ') + f
185
+ }
186
+ exit 0
187
+ }
188
+
189
+ return o if ! simple
190
+ end
191
+
192
+ begin
193
+ o.parse!(src)
194
+ @cl_parsing_times += 1
195
+ rescue
196
+ Utils.errx(1, $!.to_s)
197
+ end
198
+ end
199
+
200
+ end # Utils
201
+ end
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+ # -*-ruby-*-
3
+
4
+ require_relative '../lib/falsework/mould'
5
+
6
+ # Search for all files in the project (except .git directory) for the line
7
+ #
8
+ # /^..? :erb:/
9
+ #
10
+ # in first 4 lines. If the line is found, the file is considered a
11
+ # skeleton for a template. Return a hash {target:template}
12
+ def erb_skeletons(local_prj, template)
13
+ line_max = 4
14
+ target = File.absolute_path("lib/#{local_prj}/templates/#{template}")
15
+ r = {}
16
+ skiplist = ['/.git[^i]?', template, '/html', '/pkg', '/test/templates',
17
+ 'find_erb_templates.rb']
18
+
19
+ Falsework::Mould.traverse('.') {|i|
20
+ next if File.directory?(i)
21
+ next if File.symlink?(i)
22
+ if skiplist.index {|ign| i.match(/\/?#{ign}\/?/) }
23
+ # puts "skipped: #{i}"
24
+ next
25
+ end
26
+ # puts "looking into: #{i}"
27
+
28
+ File.open(i) {|fp|
29
+ n = 0
30
+ while n < line_max && line = fp.gets
31
+ # puts line
32
+ if line =~ /^..? :erb:/
33
+ t = i.sub(/^.+?\//, '')
34
+ r[target + '/' + t.sub(/#{local_prj}/, '.@project.') + '.erb'] = t
35
+ break
36
+ end
37
+ n += 1
38
+ end
39
+ }
40
+ }
41
+
42
+ r
43
+ end
44
+
45
+ def erb_make(local_prj, target, template)
46
+ raw = File.read(template)
47
+ raw.gsub!(/#{local_prj}/, '<%= @project %>')
48
+ raw.gsub!(/#{local_prj.capitalize}/, '<%= @project.capitalize %>')
49
+
50
+ mark = <<-EOF
51
+
52
+ # Don't remove this: <%= DateTime.now %> <%= #{local_prj.capitalize}::Meta::NAME %> <%= #{local_prj.capitalize}::Meta::VERSION %>
53
+ EOF
54
+ File.open(target, 'w+') {
55
+ |fp| fp.puts raw + ERB.new(mark).result(binding)
56
+ }
57
+ end
58
+
59
+
60
+ pp erb_skeletons(Falsework::Meta::NAME, 'naive') if __FILE__ == $0
data/test/helper.rb ADDED
@@ -0,0 +1,46 @@
1
+ # :erb:
2
+ # Various staff for minitest.
3
+
4
+ require 'fileutils'
5
+ require 'open4'
6
+
7
+ include FileUtils
8
+
9
+ require_relative '../lib/falsework/utils'
10
+ include Falsework
11
+
12
+ # don't run tests automatically if they were invoked as 'gem check -t ...'
13
+ if $0 =~ /gem/
14
+ require 'minitest/unit'
15
+ else
16
+ require 'minitest/autorun'
17
+ end
18
+
19
+ def cmd_run(cmd)
20
+ so = sr = ''
21
+ status = Open4::popen4(cmd) { |pid, stdin, stdout, stderr|
22
+ so = stdout.read
23
+ sr = stderr.read
24
+ }
25
+ [status.exitstatus, sr, so]
26
+ end
27
+
28
+ # Return the right directory for (probably executable) _c_.
29
+ def cmd(c)
30
+ case File.basename(Dir.pwd)
31
+ when Meta::NAME.downcase
32
+ # test probably is executed from the Rakefile
33
+ Dir.chdir('test')
34
+ when 'test'
35
+ # we are in the test directory, there is nothing special to do
36
+ else
37
+ # tests were invoked by 'gem check -t falsework'
38
+ begin
39
+ Dir.chdir(Utils.gem_libdir + '/../../test')
40
+ rescue
41
+ raise "running tests from '#{Dir.pwd}' isn't supported: #{$!}"
42
+ end
43
+ end
44
+
45
+ '../bin/' + c
46
+ end
File without changes