falsework 0.0.1

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.
@@ -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