rom-files 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +112 -0
  6. data/.rubocop_todo.yml +7 -0
  7. data/.ruby-version +1 -0
  8. data/.simplecov +6 -0
  9. data/.travis.yml +24 -0
  10. data/.yardopts +6 -0
  11. data/CHANGELOG.md +10 -0
  12. data/Gemfile +25 -0
  13. data/Guardfile +48 -0
  14. data/LICENSE.md +21 -0
  15. data/README.md +44 -0
  16. data/Rakefile +37 -0
  17. data/Roadmap.taskpaper +44 -0
  18. data/bin/_guard-core +21 -0
  19. data/bin/console +7 -0
  20. data/bin/guard +21 -0
  21. data/bin/rake +21 -0
  22. data/bin/rspec +21 -0
  23. data/bin/yard +21 -0
  24. data/bin/yardoc +21 -0
  25. data/bin/yri +21 -0
  26. data/lib/dry/types/pathname.rb +25 -0
  27. data/lib/pathname/extensions.rb +32 -0
  28. data/lib/pathname/extensions/constants.rb +12 -0
  29. data/lib/pathname/extensions/explode.rb +27 -0
  30. data/lib/pathname/extensions/ext.rb +28 -0
  31. data/lib/pathname/extensions/partial.rb +30 -0
  32. data/lib/pathname/extensions/pathmap.rb +128 -0
  33. data/lib/rom-files.rb +3 -0
  34. data/lib/rom/files.rb +28 -0
  35. data/lib/rom/files/associations.rb +6 -0
  36. data/lib/rom/files/associations/many_to_many.rb +12 -0
  37. data/lib/rom/files/associations/many_to_one.rb +12 -0
  38. data/lib/rom/files/associations/one_to_many.rb +12 -0
  39. data/lib/rom/files/associations/one_to_one.rb +12 -0
  40. data/lib/rom/files/attribute.rb +21 -0
  41. data/lib/rom/files/commands/create.rb +18 -0
  42. data/lib/rom/files/commands/delete.rb +17 -0
  43. data/lib/rom/files/commands/update.rb +17 -0
  44. data/lib/rom/files/connection.rb +120 -0
  45. data/lib/rom/files/constants.rb +16 -0
  46. data/lib/rom/files/dataset.rb +89 -0
  47. data/lib/rom/files/dataset/filtering.rb +96 -0
  48. data/lib/rom/files/dataset/mime_type.rb +44 -0
  49. data/lib/rom/files/dataset/paths.rb +79 -0
  50. data/lib/rom/files/dataset/sorting.rb +27 -0
  51. data/lib/rom/files/extensions.rb +30 -0
  52. data/lib/rom/files/extensions/gem.rb +29 -0
  53. data/lib/rom/files/extensions/gem/relations/documentations.rb +18 -0
  54. data/lib/rom/files/extensions/gem/relations/executables.rb +20 -0
  55. data/lib/rom/files/extensions/gem/relations/implementations.rb +29 -0
  56. data/lib/rom/files/extensions/gem/relations/specifications.rb +29 -0
  57. data/lib/rom/files/extensions/markdown/attributes_inferrer.rb +20 -0
  58. data/lib/rom/files/extensions/markdown/types.rb +18 -0
  59. data/lib/rom/files/extensions/markup/attributes_inferrer.rb +32 -0
  60. data/lib/rom/files/extensions/ruby/attributes_inferrer.rb +21 -0
  61. data/lib/rom/files/extensions/ruby/types.rb +45 -0
  62. data/lib/rom/files/extensions/text/attributes_inferrer.rb +20 -0
  63. data/lib/rom/files/gateway.rb +63 -0
  64. data/lib/rom/files/plugins/configuration/gem.rb +30 -0
  65. data/lib/rom/files/plugins/relation/instrumentation.rb +28 -0
  66. data/lib/rom/files/plugins/schema/contents.rb +72 -0
  67. data/lib/rom/files/plugins/schema/mime.rb +59 -0
  68. data/lib/rom/files/plugins/schema/shebang.rb +79 -0
  69. data/lib/rom/files/plugins/schema/stat.rb +108 -0
  70. data/lib/rom/files/relation.rb +143 -0
  71. data/lib/rom/files/schema.rb +77 -0
  72. data/lib/rom/files/schema/attributes_inferrer.rb +79 -0
  73. data/lib/rom/files/schema/inferrer.rb +36 -0
  74. data/lib/rom/files/types.rb +37 -0
  75. data/lib/rom/files/version.rb +7 -0
  76. data/rom-files.gemspec +48 -0
  77. data/spec/integration/rom/files/gateway_spec.rb +28 -0
  78. data/spec/integration/rom/files/gem_spec.rb +98 -0
  79. data/spec/integration/rom/files/relations_spec.rb +63 -0
  80. data/spec/integration/rom/files/schema/inferrer_spec.rb +77 -0
  81. data/spec/lib/dry/types/pathname_spec.rb +50 -0
  82. data/spec/lib/pathname/extensions/explode_spec.rb +25 -0
  83. data/spec/lib/pathname/extensions/ext_spec.rb +33 -0
  84. data/spec/lib/pathname/extensions/partial_spec.rb +17 -0
  85. data/spec/lib/pathname/extensions/pathmap_spec.rb +147 -0
  86. data/spec/lib/rom/files/attribute_spec.rb +43 -0
  87. data/spec/lib/rom/files/connection_spec.rb +76 -0
  88. data/spec/lib/rom/files/dataset/inside_spec.rb +22 -0
  89. data/spec/lib/rom/files/dataset/mime_type_spec.rb +23 -0
  90. data/spec/lib/rom/files/dataset/recursive_question_mark_spec.rb +42 -0
  91. data/spec/lib/rom/files/dataset/recursive_spec.rb +29 -0
  92. data/spec/lib/rom/files/dataset/reject_append_spec.rb +68 -0
  93. data/spec/lib/rom/files/dataset/reject_spec.rb +26 -0
  94. data/spec/lib/rom/files/dataset/select_append_spec.rb +69 -0
  95. data/spec/lib/rom/files/dataset/select_spec.rb +38 -0
  96. data/spec/lib/rom/files/dataset/sort_spec.rb +22 -0
  97. data/spec/lib/rom/files/dataset_spec.rb +52 -0
  98. data/spec/lib/rom/files/extensions/text/attributes_inferrer_spec.rb +54 -0
  99. data/spec/lib/rom/files/gateway_spec.rb +39 -0
  100. data/spec/lib/rom/files/plugins/schema/contents_spec.rb +66 -0
  101. data/spec/lib/rom/files/plugins/schema/mime_spec.rb +66 -0
  102. data/spec/lib/rom/files/plugins/schema/stat_spec.rb +109 -0
  103. data/spec/lib/rom/files/relation/pluck_spec.rb +20 -0
  104. data/spec/lib/rom/files/relation/reject_spec.rb +22 -0
  105. data/spec/lib/rom/files/relation/select_spec.rb +35 -0
  106. data/spec/lib/rom/files/relation/sort_spec.rb +21 -0
  107. data/spec/lib/rom/files/relation/to_a_spec.rb +39 -0
  108. data/spec/lib/rom/files/relation_spec.rb +10 -0
  109. data/spec/lib/rom/files/schema/attributes_inferrer_spec.rb +45 -0
  110. data/spec/lib/rom/files/schema/inferrer_spec.rb +29 -0
  111. data/spec/lib/rom/files/schema_spec.rb +109 -0
  112. data/spec/lib/rom/files/types/mime_type_spec.rb +9 -0
  113. data/spec/lib/rom/files/types/path_spec.rb +10 -0
  114. data/spec/lib/rom/files/types_spec.rb +6 -0
  115. data/spec/shared/rom/files/files_setup.rb +19 -0
  116. data/spec/shared/rom/files/filesystem_setup.rb +10 -0
  117. data/spec/shared/rom/files/gateway_setup.rb +17 -0
  118. data/spec/shared/rom/files/media_dataset.rb +10 -0
  119. data/spec/shared/rom/files/media_files.rb +17 -0
  120. data/spec/shared/rom/files/media_relation.rb +30 -0
  121. data/spec/spec_helper.rb +10 -0
  122. metadata +421 -0
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'rom-files'
5
+ require 'rspec'
6
+
7
+ RSpec.example_group ROM::Files, 'usage with gem' do
8
+ # @param [ROM::ConfigurationDSL] config
9
+ def def_tools(config)
10
+ config.relation :tools do
11
+ dataset do
12
+ select('*') # .stat(executable: true)
13
+ end
14
+
15
+ schema 'bin' do
16
+ # use :shebang
17
+ end
18
+ end
19
+ end
20
+
21
+ # @param [ROM::ConfigurationDSL] config
22
+ def def_examples(config)
23
+ config.relation :examples do
24
+ dataset { select '**/*.rb' }
25
+
26
+ schema 'examples' do
27
+ # use :ruby
28
+ end
29
+ end
30
+ end
31
+
32
+ def def_docs(config)
33
+ config.relation :docs do
34
+ dataset { select '**/*.md' }
35
+
36
+ schema 'text/markdown' do
37
+ # use :contents, type: Types::Markdown
38
+ end
39
+ end
40
+ end
41
+
42
+ def def_library(config)
43
+ config.relation :implementations do
44
+ dataset { inside('lib').recursive }
45
+
46
+ schema 'lib' do
47
+ # associations do
48
+ # has_one :specification
49
+ # end
50
+ end
51
+ end
52
+ end
53
+
54
+ def def_specification(config)
55
+ config.relation :specifications do
56
+ dataset { select '**/*_spec.rb' }
57
+
58
+ schema 'spec' do
59
+ # associations do
60
+ # belongs_to :implementation
61
+ # end
62
+ end
63
+ end
64
+ end
65
+
66
+ # @return [ROM::Container]
67
+ subject(:container) do
68
+ ROM.container(:files, uri) do |config|
69
+ def_docs(config)
70
+ def_tools(config)
71
+ def_examples(config)
72
+ def_library(config)
73
+ def_specification(config)
74
+ config.relation :gem do
75
+ schema :gem do
76
+ # associations do
77
+ # has_many :implementations
78
+ # has_many :specifications
79
+ # has_many :rake_files
80
+ # end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ let(:uri) { SPEC_ROOT.dirname }
86
+ let(:library_files) { container.relations[:implementations] }
87
+
88
+ xexample 'Container usage' do
89
+ require 'pry'
90
+ binding.pry # rubocop:disable Lint/Debugger
91
+ end
92
+
93
+ example 'List library files' do
94
+ expect(library_files.to_a).to be_a Array
95
+ end
96
+ end
97
+
98
+ require 'rspec/autorun' if $PROGRAM_NAME == __FILE__
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'rom-files'
5
+ require 'rspec'
6
+
7
+ RSpec.example_group ROM::Files::Relation do
8
+ Files = ROM::Files
9
+ Types = Files::Types
10
+
11
+ class Implementations < ROM::Files::Relation
12
+ dataset { select('*.rb').recursive }
13
+ schema :lib, as: :implementations do
14
+ attribute Files::ID, Types::Coercible::Pathname
15
+
16
+ primary_key Files::ID
17
+ end
18
+ end
19
+
20
+ class Specifications < ROM::Files::Relation
21
+ dataset { select('*_spec.rb').recursive }
22
+ schema :spec, as: :specifications do
23
+ attribute Files::ID, Types::Path
24
+ end
25
+ end
26
+
27
+ class TempFiles < ROM::Files::Relation
28
+ dataset { recursive }
29
+ schema :tmp, as: :temporary_files do
30
+ attribute Files::ID, Types::Pathname.meta(primary_key: true)
31
+ end
32
+ end
33
+
34
+ let(:configuration) do
35
+ ROM::Configuration.new(:files, Pathname(__dir__).dirname) do |config|
36
+ config.register_relation(Implementations)
37
+ config.register_relation(Specifications)
38
+ config.register_relation(TempFiles)
39
+ end
40
+ end
41
+ let(:container) { ROM.container(configuration) }
42
+
43
+ example 'Retrieving relations' do
44
+ p container
45
+
46
+ lib = container.relations[:implementations]
47
+ spec = container.relations[:specifications]
48
+ tmp = container.relations[:temporary_files]
49
+
50
+ expect(lib).to be_a Implementations
51
+ expect(spec).to be_a Specifications
52
+ expect(tmp).to be_a TempFiles
53
+
54
+ puts "lib #=> #{lib.inspect}"
55
+ puts 'pluck(:to_s) #=>', lib.pluck(:to_s)
56
+ # p :to_a, lib.to_a
57
+ puts 'spec #=>', spec.pluck(:basename)
58
+
59
+ puts "tmp #=> #{tmp.to_a}"
60
+ end
61
+ end
62
+
63
+ require 'rspec/autorun' if $PROGRAM_NAME == __FILE__
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/schema/inferrer'
4
+ require 'shared/rom/files/media_files'
5
+
6
+ RSpec.describe 'Schema inference for common file types' do
7
+ include_context 'media files'
8
+
9
+ let(:relation) { container.relations[relation_name] }
10
+ let(:schema) { relation.schema }
11
+ let(:source) { schema.name }
12
+ let(:relation_name) { dataset }
13
+
14
+ describe 'inferring attributes' do
15
+ before do
16
+ name = dataset
17
+ configuration.relation(relation_name) { schema(name, infer: true) }
18
+ end
19
+
20
+ context 'for any file set' do
21
+ let(:dataset) { :media }
22
+
23
+ describe '__FILE__' do
24
+ subject(:attribute) { schema[:__FILE__] }
25
+
26
+ its(:source) { is_expected.to eql source }
27
+ its('type.primitive') { is_expected.to be Pathname }
28
+ end
29
+ end
30
+
31
+ context 'for `text/plain` file set' do
32
+ let(:relation_name) { :texts }
33
+ let(:dataset) { 'text/plain' }
34
+
35
+ describe '__FILE__' do
36
+ subject(:attribute) { schema[:__FILE__] }
37
+
38
+ its(:source) { is_expected.to eql source }
39
+ its('type.primitive') { is_expected.to be Pathname }
40
+ end
41
+
42
+ describe 'DATA' do
43
+ subject(:attribute) { schema[:DATA] }
44
+
45
+ its(:source) { is_expected.to eql source }
46
+ its('type.primitive') { is_expected.to be String }
47
+
48
+ it 'autoloads contents' do
49
+ expect(attribute.meta[:DATA]).to be(true)
50
+ end
51
+ end
52
+ end
53
+
54
+ context 'for `text/markdown` file set' do
55
+ let(:relation_name) { :texts }
56
+ let(:dataset) { 'text/markdown' }
57
+
58
+ describe '__FILE__' do
59
+ subject(:attribute) { schema[:__FILE__] }
60
+
61
+ its(:source) { is_expected.to eql source }
62
+ its('type.primitive') { is_expected.to be Pathname }
63
+ end
64
+
65
+ describe 'DATA' do
66
+ subject(:attribute) { schema[:DATA] }
67
+
68
+ its(:source) { is_expected.to eql source }
69
+ its('type.primitive') { is_expected.to be Kramdown::Document }
70
+
71
+ it 'autoloads contents' do
72
+ expect(attribute.meta[:DATA]).to be(true)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/types/pathname'
4
+
5
+ RSpec.describe Dry::Types do
6
+ subject(:types) { described_class }
7
+ specify { expect(types['optional.pathname']).to be_a Dry::Types::Sum }
8
+
9
+ describe 'pathname' do
10
+ subject(:type) { types['pathname'] }
11
+
12
+ it { is_expected.to be_a Dry::Types::Definition }
13
+
14
+ specify { expect(type[nil]).to eq nil }
15
+ specify { expect(type['sample.rb']).to eq 'sample.rb' }
16
+ specify { expect(type[Pathname('sample.rb')]).to eq Pathname('sample.rb') }
17
+ end
18
+
19
+ describe 'optional.pathname' do
20
+ subject(:type) { types['optional.pathname'] }
21
+
22
+ it { is_expected.to be_a Dry::Types::Sum }
23
+
24
+ specify { expect(type[nil]).to eq nil }
25
+ specify { expect(type['sample.rb']).to eq 'sample.rb' }
26
+ specify { expect(type[Pathname('sample.rb')]).to eq Pathname('sample.rb') }
27
+ end
28
+
29
+ describe 'coercible.pathname' do
30
+ subject(:type) { types['coercible.pathname'] }
31
+
32
+ it { is_expected.to be_a Dry::Types::Definition }
33
+
34
+ specify { expect(type[nil]).to eq Pathname('') }
35
+ specify { expect(type[:media]).to eq Pathname('media') }
36
+ specify { expect(type['sample.rb']).to eq Pathname('sample.rb') }
37
+ specify { expect(type[Pathname('sample.rb')]).to eq Pathname('sample.rb') }
38
+ end
39
+
40
+ describe 'strict.pathname' do
41
+ subject(:type) { types['strict.pathname'] }
42
+
43
+ it { is_expected.to be_a Dry::Types::Constrained }
44
+
45
+ specify { expect { type[nil] }.to raise_error Dry::Types::ConstraintError }
46
+ specify { expect { type['sample.rb'] }.to raise_error Dry::Types::ConstraintError }
47
+ specify { expect { type[Pathname('sample.rb')] }.not_to raise_error }
48
+ specify { expect(type[Pathname('sample.rb')]).to eq Pathname('sample.rb') }
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname/extensions'
4
+
5
+ RSpec.describe Pathname do
6
+ before { described_class.load_extensions :explode }
7
+
8
+ describe '#explode' do
9
+ specify { expect(Pathname('a').explode).to eq [Pathname('a')] }
10
+ specify { expect(Pathname('a/b').explode).to eq [Pathname('a'), Pathname('b')] }
11
+ specify { expect(Pathname('a/b/c').explode).to eq [Pathname('a'), Pathname('b'), Pathname('c')] }
12
+ specify { expect(Pathname('/a').explode).to eq [Pathname('/'), Pathname('a')] }
13
+ specify { expect(Pathname('/a/b').explode).to eq [Pathname('/'), Pathname('a'), Pathname('b')] }
14
+ specify { expect(Pathname('/a/b/c').explode).to eq [Pathname('/'), Pathname('a'), Pathname('b'), Pathname('c')] }
15
+
16
+ if File::ALT_SEPARATOR
17
+ specify { expect(Pathname('c:a').explode).to eq [Pathname('c:.'), Pathname('a')] }
18
+ specify { expect(Pathname('c:a/b').explode).to eq [Pathname('c:.'), Pathname('a'), Pathname('b')] }
19
+ specify { expect(Pathname('c:a/b/c').explode).to eq [Pathname('c:.'), Pathname('a'), Pathname('b'), Pathname('c')] }
20
+ specify { expect(Pathname('c:/a').explode).to eq [Pathname('c:/'), Pathname('a')] }
21
+ specify { expect(Pathname('c:/a/b').explode).to eq [Pathname('c:/'), Pathname('a'), Pathname('b')] }
22
+ specify { expect(Pathname('c:/a/b/c').explode).to eq [Pathname('c:/'), Pathname('a'), Pathname('b'), Pathname('c')] }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname/extensions'
4
+
5
+ RSpec.describe Pathname do
6
+ before { described_class.load_extensions :ext }
7
+
8
+ describe '#ext' do
9
+ specify { expect(Pathname('one.two').ext('net')).to eq Pathname('one.net') }
10
+ specify { expect(Pathname('one.two').ext('.net')).to eq Pathname('one.net') }
11
+ specify { expect(Pathname('one').ext('net')).to eq Pathname('one.net') }
12
+ specify { expect(Pathname('one').ext('.net')).to eq Pathname('one.net') }
13
+ specify { expect(Pathname('one.two.c').ext('.net')).to eq Pathname('one.two.net') }
14
+ specify { expect(Pathname('one/two.c').ext('.net')).to eq Pathname('one/two.net') }
15
+ specify { expect(Pathname('one.x/two.c').ext('.net')).to eq Pathname('one.x/two.net') }
16
+ specify { expect(Pathname('one.x/two').ext('.net')).to eq Pathname('one.x/two.net') }
17
+ specify { expect(Pathname('.onerc.dot').ext('net')).to eq Pathname('.onerc.net') }
18
+ specify { expect(Pathname('.onerc').ext('net')).to eq Pathname('.onerc.net') }
19
+ specify { expect(Pathname('.a/.onerc').ext('net')).to eq Pathname('.a/.onerc.net') }
20
+ specify { expect(Pathname('one.two').ext('')).to eq Pathname('one') }
21
+ specify { expect(Pathname('one.two').ext).to eq Pathname('one') }
22
+ specify { expect(Pathname('.one.two').ext).to eq Pathname('.one') }
23
+ specify { expect(Pathname('.one').ext).to eq Pathname('.one') }
24
+ specify { expect(Pathname('.').ext('c')).to eq Pathname('.') }
25
+ specify { expect(Pathname('..').ext('c')).to eq Pathname('..') }
26
+
27
+ # These only need to work in windows
28
+ if RbConfig::CONFIG['host_os'].match?(/(msdos|mswin|djgpp|mingw|[Ww]indows)/)
29
+ specify { expect(Pathname('one.x\\two.c').ext('.net')).to eq Pathname('one.x\\two.net') }
30
+ specify { expect(Pathname('one.x\\two').ext('.net')).to eq Pathname('one.x\\two.net') }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname/extensions'
4
+
5
+ RSpec.describe Pathname do
6
+ before { described_class.load_extensions :partial }
7
+
8
+ describe '#partial' do
9
+ specify { expect(Pathname('1/2/file').partial(1)).to eq Pathname('1') }
10
+ specify { expect(Pathname('1/2/file').partial(2)).to eq Pathname('1/2') }
11
+ specify { expect(Pathname('1/2/file').partial(3)).to eq Pathname('1/2') }
12
+ specify { expect(Pathname('1/2/file').partial(0)).to eq Pathname('.') }
13
+ specify { expect(Pathname('1/2/file').partial(-1)).to eq Pathname('2') }
14
+ specify { expect(Pathname('1/2/file').partial(-2)).to eq Pathname('1/2') }
15
+ specify { expect(Pathname('1/2/file').partial(-3)).to eq Pathname('1/2') }
16
+ end
17
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname/extensions'
4
+
5
+ RSpec.describe Pathname do
6
+ before { described_class.load_extensions :pathmap }
7
+
8
+ it 'returns_self_with_no_args', :aggregate_failures do
9
+ expect(Pathname('abc.rb').pathmap).to eq Pathname('abc.rb')
10
+ end
11
+
12
+ it 's_returns_file_separator', :aggregate_failures do
13
+ sep = File::ALT_SEPARATOR || File::SEPARATOR
14
+ expect(Pathname('abc.rb').pathmap('%s')).to eq Pathname(sep)
15
+ expect(Pathname('').pathmap('%s')).to eq Pathname(sep)
16
+ expect(Pathname('a/b').pathmap('%d%s%f')).to eq Pathname("a#{sep}b")
17
+ end
18
+
19
+ it 'f_returns_basename', :aggregate_failures do
20
+ expect(Pathname('abc.rb').pathmap('%f')).to eq Pathname('abc.rb')
21
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%f')).to eq Pathname('abc.rb')
22
+ expect(Pathname('/this/is/a/dir/abc.rb').pathmap('%f')).to eq Pathname('abc.rb')
23
+ end
24
+
25
+ it 'n_returns_basename_without_extension', :aggregate_failures do
26
+ expect(Pathname('abc.rb').pathmap('%n')).to eq Pathname('abc')
27
+ expect(Pathname('abc').pathmap('%n')).to eq Pathname('abc')
28
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%n')).to eq Pathname('abc')
29
+ expect(Pathname('/this/is/a/dir/abc.rb').pathmap('%n')).to eq Pathname('abc')
30
+ expect(Pathname('/this/is/a/dir/abc').pathmap('%n')).to eq Pathname('abc')
31
+ end
32
+
33
+ it 'd_returns_dirname', :aggregate_failures do
34
+ expect(Pathname('abc.rb').pathmap('%d')).to eq Pathname('.')
35
+ expect(Pathname('/abc').pathmap('%d')).to eq Pathname('/')
36
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%d')).to eq Pathname('this/is/a/dir')
37
+ expect(Pathname('/this/is/a/dir/abc.rb').pathmap('%d')).to eq Pathname('/this/is/a/dir')
38
+ end
39
+
40
+ it '9d_returns_partial_dirname', :aggregate_failures do
41
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%2d')).to eq Pathname('this/is')
42
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%1d')).to eq Pathname('this')
43
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%0d')).to eq Pathname('.')
44
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%-1d')).to eq Pathname('dir')
45
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%-2d')).to eq Pathname('a/dir')
46
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%100d')).to eq Pathname('this/is/a/dir')
47
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%-100d')).to eq Pathname('this/is/a/dir')
48
+ end
49
+
50
+ it 'x_returns_extension', :aggregate_failures do
51
+ expect(Pathname('abc').pathmap('%x')).to eq Pathname('')
52
+ expect(Pathname('abc.rb').pathmap('%x')).to eq Pathname('.rb')
53
+ expect(Pathname('abc.xyz.rb').pathmap('%x')).to eq Pathname('.rb')
54
+ expect(Pathname('.depends').pathmap('%x')).to eq Pathname('')
55
+ expect(Pathname('dir/.depends').pathmap('%x')).to eq Pathname('')
56
+ end
57
+
58
+ it 'x_returns_everything_but_extension', :aggregate_failures do
59
+ expect(Pathname('abc').pathmap('%X')).to eq Pathname('abc')
60
+ expect(Pathname('abc.rb').pathmap('%X')).to eq Pathname('abc')
61
+ expect(Pathname('abc.xyz.rb').pathmap('%X')).to eq Pathname('abc.xyz')
62
+ expect(Pathname('ab.xyz.rb').pathmap('%X')).to eq Pathname('ab.xyz')
63
+ expect(Pathname('a.xyz.rb').pathmap('%X')).to eq Pathname('a.xyz')
64
+ expect(Pathname('abc.rb').pathmap('%X')).to eq Pathname('abc')
65
+ expect(Pathname('ab.rb').pathmap('%X')).to eq Pathname('ab')
66
+ expect(Pathname('a.rb').pathmap('%X')).to eq Pathname('a')
67
+ expect(Pathname('.depends').pathmap('%X')).to eq Pathname('.depends')
68
+ expect(Pathname('a/dir/.depends').pathmap('%X')).to eq Pathname('a/dir/.depends')
69
+ expect(Pathname('/.depends').pathmap('%X')).to eq Pathname('/.depends')
70
+ end
71
+
72
+ it 'p_returns_entire_pathname', :aggregate_failures do
73
+ expect(Pathname('abc.rb').pathmap('%p')).to eq Pathname('abc.rb')
74
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%p')).to eq Pathname('this/is/a/dir/abc.rb')
75
+ expect(Pathname('/this/is/a/dir/abc.rb').pathmap('%p')).to eq Pathname('/this/is/a/dir/abc.rb')
76
+ end
77
+
78
+ it 'dash_returns_empty_string', :aggregate_failures do
79
+ expect(Pathname('abc.rb').pathmap('%-')).to eq Pathname('')
80
+ expect(Pathname('abc.rb').pathmap('%X%-%x')).to eq Pathname('abc.rb')
81
+ end
82
+
83
+ it 'percent_percent_returns_percent', :aggregate_failures do
84
+ expect(Pathname('').pathmap('a%%b')).to eq Pathname('a%b')
85
+ end
86
+
87
+ it 'undefined_percent_causes_error', :aggregate_failures do
88
+ expect { Pathname('dir/abc.rb').pathmap('%z') }.to raise_error ArgumentError
89
+ end
90
+
91
+ it 'pattern_returns_substitutions', :aggregate_failures do
92
+ expect(Pathname('src/org/osb/Xyz.java').pathmap('%{src,bin}d')).to eq Pathname('bin/org/osb')
93
+ end
94
+
95
+ it 'pattern_can_use_backreferences', :aggregate_failures do
96
+ expect(Pathname('dir/this/is').pathmap('%{t(hi)s,\\1}p')).to eq Pathname('dir/hi/is')
97
+ end
98
+
99
+ it 'pattern_with_star_replacement_string_uses_block', :aggregate_failures do
100
+ expect(Pathname('src/org/osb/Xyz.java').pathmap('%{/org,*}d', &:upcase)).to eq Pathname('src/ORG/osb')
101
+ expect(Pathname('src/org/osb/Xyz.java').pathmap('%{.*,*}f', &:capitalize)).to eq Pathname('Xyz.java')
102
+ end
103
+
104
+ it 'pattern_with_no_replacement_nor_block_substitutes_empty_string', :aggregate_failures do
105
+ expect(Pathname('abc.rb').pathmap('%{a}f')).to eq Pathname('bc.rb')
106
+ end
107
+
108
+ it 'pattern_works_with_certain_valid_operators', :aggregate_failures do
109
+ expect(Pathname('dir/abc.rb').pathmap('%{a,x}p')).to eq Pathname('dir/xbc.rb')
110
+ expect(Pathname('dir/abc.rb').pathmap('%{i,1}d')).to eq Pathname('d1r')
111
+ expect(Pathname('dir/abc.rb').pathmap('%{a,x}f')).to eq Pathname('xbc.rb')
112
+ expect(Pathname('dir/abc.rb').pathmap('%{r,R}x')).to eq Pathname('.Rb')
113
+ expect(Pathname('dir/abc.rb').pathmap('%{a,x}n')).to eq Pathname('xbc')
114
+ end
115
+
116
+ it 'multiple_patterns', :aggregate_failures do
117
+ expect(Pathname('this/is/a/dir/abc.rb').pathmap('%{a,b;dir,\\0ectory}p')).to eq Pathname('this/is/b/directory/abc.rb')
118
+ end
119
+
120
+ it 'partial_directory_selection_works_with_patterns', :aggregate_failures do
121
+ expect(Pathname('this/is/a/really/long/path/ok.rb').pathmap('%{/really/,/}5d')).to eq Pathname('this/is/a/long')
122
+ end
123
+
124
+ it 'pattern_with_invalid_operator', :aggregate_failures do
125
+ expect do
126
+ Pathname('abc.xyz').pathmap('%{src,bin}z')
127
+ end.to raise_error ArgumentError, /unknown.*pathmap.*spec.*z/i
128
+ end
129
+
130
+ it 'works_with_windows_separators', :aggregate_failures do
131
+ if File::ALT_SEPARATOR
132
+ expect(Pathname('dir\abc.rb').pathmap('%n')).to eq Pathname('abc')
133
+ expect(Pathname('this\is\a\dir\abc.rb').pathmap('%d')).to eq Pathname('this\is\a\dir')
134
+ end
135
+ end
136
+
137
+ it 'complex_patterns', :aggregate_failures do
138
+ sep = Pathname('').pathmap('%s')
139
+ expect(Pathname('dir/abc.rb').pathmap('%d/%n%x')).to eq Pathname('dir/abc.rb')
140
+ expect(Pathname('abc.rb').pathmap('%d/%n%x')).to eq Pathname('./abc.rb')
141
+ expect(Pathname('dir/abc.rb').pathmap("Your file extension is '%x'")).to eq Pathname("Your file extension is '.rb'")
142
+ expect(Pathname('src/org/onestepback/proj/A.java').pathmap('%{src,bin}d/%n.class')).to eq Pathname('bin/org/onestepback/proj/A.class')
143
+ expect(Pathname('src_work/src/org/onestepback/proj/A.java').pathmap('%{\bsrc\b,bin}X.class')).to eq Pathname('src_work/bin/org/onestepback/proj/A.class')
144
+ expect(Pathname('.depends').pathmap('%X.bak')).to eq Pathname('.depends.bak')
145
+ expect(Pathname('a/b/c/d/file.txt').pathmap('%-1d%s%3d%s%f')).to eq Pathname("d#{sep}a/b/c#{sep}file.txt")
146
+ end
147
+ end