ext 0.0.5
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/MIT_LICENSE.txt +22 -0
- data/README +108 -0
- data/Rakefile +64 -0
- data/bin/ext +5 -0
- data/bin/ext.bat +6 -0
- data/lib/ext/string.rb +9 -0
- data/lib/ext/symbol.rb +7 -0
- data/lib/externals/command.rb +35 -0
- data/lib/externals/configuration/configuration.rb +159 -0
- data/lib/externals/ext.rb +557 -0
- data/lib/externals/project.rb +110 -0
- data/lib/externals/project_types/rails.rb +28 -0
- data/lib/externals/scms/git_project.rb +114 -0
- data/lib/externals/scms/svn_project.rb +98 -0
- data/lib/externals/test_case.rb +97 -0
- data/test/test_checkout_git.rb +35 -0
- data/test/test_checkout_with_subprojects_git.rb +77 -0
- data/test/test_checkout_with_subprojects_svn.rb +153 -0
- data/test/test_init_git.rb +47 -0
- data/test/test_rails_detection.rb +26 -0
- data/test/test_string_extensions.rb +15 -0
- data/test/test_touch_emptydirs.rb +52 -0
- metadata +72 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib') if $0 == __FILE__
|
2
|
+
require 'externals/test_case'
|
3
|
+
require 'externals/ext'
|
4
|
+
|
5
|
+
module Externals
|
6
|
+
class TestCheckoutGit < TestCase
|
7
|
+
def setup
|
8
|
+
initialize_test_git_repository
|
9
|
+
|
10
|
+
Dir.chdir File.join(root_dir, 'test') do
|
11
|
+
`rm -rf workdir`
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
destroy_test_repository 'git'
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_repository_created
|
20
|
+
assert File.exists?(File.join(repository_dir('git'), '.git'))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_checkout
|
24
|
+
Dir.chdir File.join(root_dir, 'test') do
|
25
|
+
`mkdir workdir`
|
26
|
+
|
27
|
+
Dir.chdir 'workdir' do
|
28
|
+
Ext.run "checkout", "--git", repository_dir('git')
|
29
|
+
|
30
|
+
assert File.exists?(File.join(repository_dir('git'),'.git'))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib') if $0 == __FILE__
|
2
|
+
require 'externals/test_case'
|
3
|
+
require 'externals/ext'
|
4
|
+
|
5
|
+
module Externals
|
6
|
+
class TestCheckoutWithSubprojectsGit < TestCase
|
7
|
+
def setup
|
8
|
+
destroy_rails_application
|
9
|
+
create_rails_application
|
10
|
+
|
11
|
+
Dir.chdir File.join(root_dir, 'test') do
|
12
|
+
parts = 'workdir/checkout/rails_app/vendor/plugins/foreign_key_migrations/lib/red_hill_consulting/foreign_key_migrations/active_record/connection_adapters/.svn/text-base/table_definition.rb.svn-base'.split('/')
|
13
|
+
if File.exists? File.join(*parts)
|
14
|
+
Dir.chdir File.join(*(parts[0..-2])) do
|
15
|
+
File.delete parts[-1]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
`rm -rf workdir`
|
19
|
+
`mkdir workdir`
|
20
|
+
`cp -r #{rails_application_dir} workdir`
|
21
|
+
Dir.chdir File.join('workdir','rails_app') do
|
22
|
+
Ext.run "touch_emptydirs"
|
23
|
+
|
24
|
+
`git init`
|
25
|
+
Ext.run "init"
|
26
|
+
raise " could not create .externals" unless File.exists? '.externals'
|
27
|
+
Ext.run "install", "git://github.com/rails/acts_as_list.git"
|
28
|
+
|
29
|
+
#install a couple svn managed subprojects
|
30
|
+
%w(foreign_key_migrations redhillonrails_core).each do |proj|
|
31
|
+
Ext.run "install", "svn://rubyforge.org/var/svn/redhillonrails/trunk/vendor/plugins/#{proj}"
|
32
|
+
end
|
33
|
+
|
34
|
+
GitProject.add_all
|
35
|
+
`git commit -m "created empty rails app with some subprojects"`
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def teardown
|
41
|
+
destroy_rails_application
|
42
|
+
|
43
|
+
# Dir.chdir File.join(root_dir, 'test') do
|
44
|
+
# `rm -rf workdir`
|
45
|
+
# end
|
46
|
+
#XXX
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def test_checkout_with_subproject
|
51
|
+
Dir.chdir File.join(root_dir, 'test') do
|
52
|
+
Dir.chdir 'workdir' do
|
53
|
+
`mkdir checkout`
|
54
|
+
Dir.chdir 'checkout' do
|
55
|
+
source = File.join(root_dir, 'test', 'workdir', 'rails_app')
|
56
|
+
puts "About to checkout #{ source}"
|
57
|
+
Ext.run "checkout", "--git", source
|
58
|
+
|
59
|
+
Dir.chdir 'rails_app' do
|
60
|
+
assert File.exists?('.git')
|
61
|
+
|
62
|
+
assert File.exists?('.gitignore')
|
63
|
+
|
64
|
+
%w(foreign_key_migrations redhillonrails_core acts_as_list).each do |proj|
|
65
|
+
assert(File.read('.gitignore') =~ /^vendor[\/\\]plugins[\/\\]#{proj}$/)
|
66
|
+
end
|
67
|
+
|
68
|
+
%w(foreign_key_migrations redhillonrails_core acts_as_list).each do |proj|
|
69
|
+
assert File.exists?(File.join('vendor', 'plugins',proj, 'lib'))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib') if $0 == __FILE__
|
2
|
+
require 'externals/test_case'
|
3
|
+
require 'externals/ext'
|
4
|
+
|
5
|
+
module Externals
|
6
|
+
class TestCheckoutWithSubprojectsSvn < TestCase
|
7
|
+
def setup
|
8
|
+
destroy_rails_application
|
9
|
+
create_rails_application
|
10
|
+
destroy_test_repository 'svn'
|
11
|
+
initialize_test_svn_repository
|
12
|
+
|
13
|
+
Dir.chdir File.join(root_dir, 'test') do
|
14
|
+
parts = 'workdir/checkout/rails_app/vendor/plugins/foreign_key_migrations/lib/red_hill_consulting/foreign_key_migrations/active_record/connection_adapters/.svn/text-base/table_definition.rb.svn-base'.split('/')
|
15
|
+
if File.exists? File.join(*parts)
|
16
|
+
Dir.chdir File.join(*(parts[0..-2])) do
|
17
|
+
File.delete parts[-1]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
`rm -rf workdir`
|
22
|
+
repo_url = repository_dir('svn')
|
23
|
+
if windows?
|
24
|
+
repo_url = repo_url.gsub(/\\/, "/")
|
25
|
+
end
|
26
|
+
|
27
|
+
puts `svn co file:///#{repository_dir('svn')} #{File.join("workdir","rails_app")}`
|
28
|
+
Dir.chdir File.join('workdir', "rails_app") do
|
29
|
+
puts `cp -r #{rails_application_dir}/* .`
|
30
|
+
|
31
|
+
SvnProject.add_all
|
32
|
+
|
33
|
+
Ext.run "init"
|
34
|
+
raise " could not create .externals" unless File.exists? '.externals'
|
35
|
+
%w(rails acts_as_list).each do |proj|
|
36
|
+
Ext.run "install", "git://github.com/rails/#{proj}.git"
|
37
|
+
end
|
38
|
+
|
39
|
+
#install a couple svn managed subprojects
|
40
|
+
%w(foreign_key_migrations redhillonrails_core).each do |proj|
|
41
|
+
Ext.run "install", "svn://rubyforge.org/var/svn/redhillonrails/trunk/vendor/plugins/#{proj}"
|
42
|
+
end
|
43
|
+
|
44
|
+
SvnProject.add_all
|
45
|
+
|
46
|
+
puts `svn commit -m "created empty rails app with some subprojects"`
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def teardown
|
52
|
+
destroy_rails_application
|
53
|
+
|
54
|
+
# Dir.chdir File.join(root_dir, 'test') do
|
55
|
+
# `rm -rf workdir`
|
56
|
+
# end
|
57
|
+
#XXX
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def test_checkout_with_subproject
|
62
|
+
Dir.chdir File.join(root_dir, 'test') do
|
63
|
+
Dir.chdir 'workdir' do
|
64
|
+
`mkdir checkout`
|
65
|
+
Dir.chdir 'checkout' do
|
66
|
+
source = repository_dir('svn')
|
67
|
+
|
68
|
+
if windows?
|
69
|
+
source = source.gsub(/\\/, "/")
|
70
|
+
end
|
71
|
+
source = "file:///#{source}"
|
72
|
+
|
73
|
+
|
74
|
+
puts "About to checkout #{source}"
|
75
|
+
Ext.run "checkout", "--svn", source, 'rails_app'
|
76
|
+
|
77
|
+
Dir.chdir 'rails_app' do
|
78
|
+
assert File.exists?('.svn')
|
79
|
+
|
80
|
+
%w(foreign_key_migrations redhillonrails_core acts_as_list).each do |proj|
|
81
|
+
puts(ignore_text = `svn propget svn:ignore vendor/plugins`)
|
82
|
+
assert(ignore_text =~ /^#{proj}$/)
|
83
|
+
end
|
84
|
+
|
85
|
+
puts(ignore_text = `svn propget svn:ignore vendor`)
|
86
|
+
assert(ignore_text =~ /^rails$/)
|
87
|
+
|
88
|
+
Dir.chdir File.join('vendor', 'rails') do
|
89
|
+
assert `git show 92f944818eece9fe4bc62ffb39accdb71ebc32be` =~ /azimux/
|
90
|
+
end
|
91
|
+
|
92
|
+
%w(foreign_key_migrations redhillonrails_core acts_as_list).each do |proj|
|
93
|
+
assert File.exists?(File.join('vendor', 'plugins',proj, 'lib'))
|
94
|
+
end
|
95
|
+
|
96
|
+
assert File.exists?(File.join('vendor', 'rails', 'activerecord', 'lib'))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_export_with_subproject
|
104
|
+
Dir.chdir File.join(root_dir, 'test') do
|
105
|
+
Dir.chdir 'workdir' do
|
106
|
+
`mkdir export`
|
107
|
+
Dir.chdir 'export' do
|
108
|
+
source = repository_dir('svn')
|
109
|
+
|
110
|
+
if windows?
|
111
|
+
source = source.gsub(/\\/, "/")
|
112
|
+
end
|
113
|
+
source = "file:///#{source}"
|
114
|
+
|
115
|
+
|
116
|
+
puts "About to export #{source}"
|
117
|
+
Ext.run "export", "--svn", source, 'rails_app'
|
118
|
+
|
119
|
+
Dir.chdir 'rails_app' do
|
120
|
+
assert File.exists?('.svn')
|
121
|
+
|
122
|
+
%w(foreign_key_migrations redhillonrails_core acts_as_list).each do |proj|
|
123
|
+
puts(ignore_text = `svn propget svn:ignore vendor/plugins`)
|
124
|
+
assert(ignore_text =~ /^#{proj}$/)
|
125
|
+
end
|
126
|
+
|
127
|
+
puts(ignore_text = `svn propget svn:ignore vendor`)
|
128
|
+
assert(ignore_text =~ /^rails$/)
|
129
|
+
|
130
|
+
Dir.chdir File.join('vendor', 'rails') do
|
131
|
+
assert `git show 92f944818eece9fe4bc62ffb39accdb71ebc32be` !~ /azimux/
|
132
|
+
end
|
133
|
+
|
134
|
+
%w(foreign_key_migrations redhillonrails_core acts_as_list).each do |proj|
|
135
|
+
puts "filethere? #{proj}: #{File.exists?(File.join('vendor', 'plugins', proj, 'lib'))}"
|
136
|
+
if !File.exists?(File.join('vendor', 'plugins', proj, 'lib'))
|
137
|
+
puts "here"
|
138
|
+
end
|
139
|
+
assert File.exists?(File.join('vendor', 'plugins', proj, 'lib'))
|
140
|
+
end
|
141
|
+
|
142
|
+
%w(foreign_key_migrations redhillonrails_core).each do |proj|
|
143
|
+
assert !File.exists?(File.join('vendor', 'plugins',proj, '.svn'))
|
144
|
+
end
|
145
|
+
|
146
|
+
assert File.exists?(File.join('vendor', 'rails', 'activerecord', 'lib'))
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib') if $0 == __FILE__
|
2
|
+
require 'externals/test_case'
|
3
|
+
require 'externals/ext'
|
4
|
+
|
5
|
+
module Externals
|
6
|
+
class TestInitGit < TestCase
|
7
|
+
def setup
|
8
|
+
initialize_test_git_repository
|
9
|
+
Dir.chdir File.join(root_dir, 'test') do
|
10
|
+
`mkdir workdir`
|
11
|
+
|
12
|
+
Dir.chdir 'workdir' do
|
13
|
+
`cp -r #{repository_dir('git')} .`
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def teardown
|
19
|
+
destroy_test_repository 'git'
|
20
|
+
|
21
|
+
Dir.chdir File.join(root_dir, 'test') do
|
22
|
+
`rm -rf workdir`
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_repository_created
|
27
|
+
assert File.exists?(File.join(repository_dir('git'), '.git'))
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_init
|
31
|
+
Dir.chdir File.join(root_dir, 'test') do
|
32
|
+
`mkdir workdir`
|
33
|
+
|
34
|
+
Dir.chdir 'workdir' do
|
35
|
+
Dir.chdir 'gitrepo' do
|
36
|
+
assert !File.exists?('.externals')
|
37
|
+
|
38
|
+
Ext.run "init"
|
39
|
+
|
40
|
+
assert File.exists?('.externals')
|
41
|
+
assert(File.read('.externals') =~ /^\s*scm\s*=\s*git\s*$/)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib') if $0 == __FILE__
|
2
|
+
|
3
|
+
require 'externals/test_case'
|
4
|
+
require 'externals/ext'
|
5
|
+
|
6
|
+
module Externals
|
7
|
+
class TestRailsDetection < TestCase
|
8
|
+
def setup
|
9
|
+
destroy_rails_application
|
10
|
+
create_rails_application
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
destroy_rails_application
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_detection
|
18
|
+
detector = Ext.project_type_detector('rails')
|
19
|
+
|
20
|
+
assert !detector.detected?
|
21
|
+
Dir.chdir(rails_application_dir) do
|
22
|
+
assert detector.detected?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib') if $0 == __FILE__
|
2
|
+
|
3
|
+
require 'externals/test_case'
|
4
|
+
require 'externals/ext'
|
5
|
+
|
6
|
+
module Externals
|
7
|
+
class TestStringExtensions < TestCase
|
8
|
+
def test_classify
|
9
|
+
assert_equal "yourmom".classify, "Yourmom"
|
10
|
+
assert_equal "your_mom".classify, "YourMom"
|
11
|
+
assert_equal "lol_your_mom".classify, "LolYourMom"
|
12
|
+
assert_equal "".classify, ""
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib') if $0 == __FILE__
|
2
|
+
|
3
|
+
require 'externals/test_case'
|
4
|
+
require 'externals/ext'
|
5
|
+
|
6
|
+
module Externals
|
7
|
+
class TestTouchEmptydirs < TestCase
|
8
|
+
def setup
|
9
|
+
Dir.chdir File.join(root_dir, 'test') do
|
10
|
+
`mkdir workdir`
|
11
|
+
|
12
|
+
Dir.chdir 'workdir' do
|
13
|
+
`mkdir notempty1`
|
14
|
+
Dir.chdir 'notempty1' do
|
15
|
+
`mkdir notempty2`
|
16
|
+
`mkdir empty1`
|
17
|
+
Dir.chdir 'notempty2' do
|
18
|
+
`mkdir empty2`
|
19
|
+
`mkdir notempty3`
|
20
|
+
Dir.chdir 'notempty3' do
|
21
|
+
File.open('readme.txt', 'w') do |f|
|
22
|
+
f.write "some text\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def teardown
|
32
|
+
Dir.chdir File.join(root_dir, 'test') do
|
33
|
+
`rm -rf workdir`
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_touch_emptydirs
|
38
|
+
Dir.chdir File.join(root_dir, 'test') do
|
39
|
+
assert !File.exists?(File.join('.emptydir'))
|
40
|
+
Dir.chdir 'workdir' do
|
41
|
+
Ext.run "touch_emptydirs"
|
42
|
+
assert !File.exists?(File.join('.emptydir'))
|
43
|
+
assert !File.exists?(File.join('notempty1', '.emptydir'))
|
44
|
+
assert File.exists?(File.join('notempty1', 'empty1', '.emptydir'))
|
45
|
+
assert !File.exists?(File.join('notempty1', 'notempty2', '.emptydir'))
|
46
|
+
assert File.exists?(File.join('notempty1', 'notempty2', 'empty2', '.emptydir'))
|
47
|
+
assert !File.exists?(File.join('notempty1', 'notempty2', 'notempty3', '.emptydir'))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ext
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Miles Georgi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-09-04 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: "Provides an SCM agnostic way to manage subprojects with a workflow similar to the scm:externals feature of subversion. It's particularly useful for rails projects that have some plugins managed by svn and some managed by git. For example, \"ext install git://github.com/rails/rails.git\" from within a rails application directory will realize that this belongs in the vendor/rails folder. It will also realize that this URL is a git repository and clone it into that folder. It will also add the vendor/rails folder to the ignore feature for the SCM of the main project. Let's say that the main project is being managed by subversion. In that case it adds \"rails\" to the svn:ignore property of the vendor folder. It also adds the URL to the .externals file so that when this project is checked out via \"ext checkout\" it knows where to fetch the subprojects. There are several other useful commands, such as init, touch_emptydirs, add_all, export, status. I plan to put up a tutorial at http://nopugs.com/ext-tutorial The reason I made this project is that I was frustrated by two things: 1. In my opinion, the workflow for svn:externals is far superior to git-submodule. 2. Even if git-submodule was as useful as svn:externals, I would still like a uniform way to fetch all of the subprojects regardless of the SCM used to manage the main project."
|
17
|
+
email: azimux@gmail.com
|
18
|
+
executables:
|
19
|
+
- ext
|
20
|
+
- ext.bat
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- Rakefile
|
27
|
+
- README
|
28
|
+
- MIT_LICENSE.txt
|
29
|
+
- lib/ext/string.rb
|
30
|
+
- lib/ext/symbol.rb
|
31
|
+
- lib/externals/command.rb
|
32
|
+
- lib/externals/configuration/configuration.rb
|
33
|
+
- lib/externals/ext.rb
|
34
|
+
- lib/externals/project.rb
|
35
|
+
- lib/externals/project_types/rails.rb
|
36
|
+
- lib/externals/scms/git_project.rb
|
37
|
+
- lib/externals/scms/svn_project.rb
|
38
|
+
- lib/externals/test_case.rb
|
39
|
+
has_rdoc: false
|
40
|
+
homepage: http://nopugs.com/ext-tutorial
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project: ext
|
61
|
+
rubygems_version: 1.2.0
|
62
|
+
signing_key:
|
63
|
+
specification_version: 2
|
64
|
+
summary: Provides an SCM agnostic way to manage subprojects with a workflow similar to the svn:externals feature of subversion. It's particularly useful for rails projects that have some plugins managed by svn and some managed by git.
|
65
|
+
test_files:
|
66
|
+
- test/test_checkout_git.rb
|
67
|
+
- test/test_checkout_with_subprojects_git.rb
|
68
|
+
- test/test_checkout_with_subprojects_svn.rb
|
69
|
+
- test/test_init_git.rb
|
70
|
+
- test/test_rails_detection.rb
|
71
|
+
- test/test_string_extensions.rb
|
72
|
+
- test/test_touch_emptydirs.rb
|