buildpack-support 1.0.0

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.
Files changed (122) hide show
  1. data/LICENSE +202 -0
  2. data/NOTICE +2 -0
  3. data/docs/cache.md +77 -0
  4. data/docs/component.md +1 -0
  5. data/docs/configuration.md +27 -0
  6. data/docs/logging.md +54 -0
  7. data/docs/other.md +1 -0
  8. data/docs/rake.md +1 -0
  9. data/docs/repository.md +116 -0
  10. data/docs/test.md +1 -0
  11. data/lib/buildpack_support.rb +18 -0
  12. data/lib/buildpack_support/base_buildpack.rb +166 -0
  13. data/lib/buildpack_support/buildpack_version.rb +124 -0
  14. data/lib/buildpack_support/cache.rb +24 -0
  15. data/lib/buildpack_support/cache/application_cache.rb +41 -0
  16. data/lib/buildpack_support/cache/cached_file.rb +103 -0
  17. data/lib/buildpack_support/cache/download_cache.rb +280 -0
  18. data/lib/buildpack_support/cache/inferred_network_failure.rb +26 -0
  19. data/lib/buildpack_support/cache/internet_availability.rb +64 -0
  20. data/lib/buildpack_support/component.rb +24 -0
  21. data/lib/buildpack_support/component/application.rb +76 -0
  22. data/lib/buildpack_support/component/base_component.rb +78 -0
  23. data/lib/buildpack_support/component/base_droplet.rb +96 -0
  24. data/lib/buildpack_support/component/downloads.rb +88 -0
  25. data/lib/buildpack_support/component/services.rb +84 -0
  26. data/lib/buildpack_support/component/versioned_dependency_component.rb +71 -0
  27. data/lib/buildpack_support/component/versioned_downloads.rb +57 -0
  28. data/lib/buildpack_support/component/with_timing.rb +40 -0
  29. data/lib/buildpack_support/configuration_utils.rb +58 -0
  30. data/lib/buildpack_support/constantize.rb +46 -0
  31. data/lib/buildpack_support/dash_case.rb +29 -0
  32. data/lib/buildpack_support/directory_finder.rb +45 -0
  33. data/lib/buildpack_support/filtering_pathname.rb +227 -0
  34. data/lib/buildpack_support/format_duration.rb +57 -0
  35. data/lib/buildpack_support/logging.rb +22 -0
  36. data/lib/buildpack_support/logging/delegating_logger.rb +48 -0
  37. data/lib/buildpack_support/logging/logger_factory.rb +148 -0
  38. data/lib/buildpack_support/qualify_path.rb +36 -0
  39. data/lib/buildpack_support/rake.rb +22 -0
  40. data/lib/buildpack_support/rake/buildpack_stage_task.rb +86 -0
  41. data/lib/buildpack_support/rake/cached_artifact_finder.rb +99 -0
  42. data/lib/buildpack_support/rake/check_api_doc_task.rb +70 -0
  43. data/lib/buildpack_support/rake/dependency_cache_task.rb +87 -0
  44. data/lib/buildpack_support/rake/disable_remote_downloads_task.rb +80 -0
  45. data/lib/buildpack_support/rake/package_task.rb +133 -0
  46. data/lib/buildpack_support/rake/package_zip_task.rb +80 -0
  47. data/lib/buildpack_support/rake/repository_configuration_finder.rb +66 -0
  48. data/lib/buildpack_support/rake/write_version_file_task.rb +82 -0
  49. data/lib/buildpack_support/repository.rb +24 -0
  50. data/lib/buildpack_support/repository/configured_item.rb +81 -0
  51. data/lib/buildpack_support/repository/repository_index.rb +98 -0
  52. data/lib/buildpack_support/repository/wildcard_version_resolver.rb +75 -0
  53. data/lib/buildpack_support/shell.rb +41 -0
  54. data/lib/buildpack_support/snake_case.rb +30 -0
  55. data/lib/buildpack_support/space_case.rb +29 -0
  56. data/lib/buildpack_support/test/application_helper.rb +41 -0
  57. data/lib/buildpack_support/test/base_component_helper.rb +59 -0
  58. data/lib/buildpack_support/test/base_droplet_helper.rb +36 -0
  59. data/lib/buildpack_support/test/console_helper.rb +57 -0
  60. data/lib/buildpack_support/test/environment_helper.rb +32 -0
  61. data/lib/buildpack_support/test/internet_availability_helper.rb +29 -0
  62. data/lib/buildpack_support/test/logging_helper.rb +50 -0
  63. data/lib/buildpack_support/test/scratch_helper.rb +32 -0
  64. data/lib/buildpack_support/test/versioned_dependency_component_helper.rb +32 -0
  65. data/lib/buildpack_support/test/with_load_path_helper.rb +27 -0
  66. data/lib/buildpack_support/to_b.rb +38 -0
  67. data/lib/buildpack_support/tokenized_version.rb +157 -0
  68. data/lib/buildpack_support/version.rb +23 -0
  69. data/spec/buildpack_support/base_buildpack_spec.rb +112 -0
  70. data/spec/buildpack_support/buildpack_version_spec.rb +122 -0
  71. data/spec/buildpack_support/cache/application_cache_spec.rb +56 -0
  72. data/spec/buildpack_support/cache/cached_file_spec.rb +94 -0
  73. data/spec/buildpack_support/cache/download_cache_spec.rb +293 -0
  74. data/spec/buildpack_support/cache/internet_availability_spec.rb +57 -0
  75. data/spec/buildpack_support/cache/yield_file_with_content.rb +30 -0
  76. data/spec/buildpack_support/component/application_spec.rb +81 -0
  77. data/spec/buildpack_support/component/base_component_spec.rb +81 -0
  78. data/spec/buildpack_support/component/base_droplet_spec.rb +72 -0
  79. data/spec/buildpack_support/component/downloads_spec.rb +63 -0
  80. data/spec/buildpack_support/component/services_spec.rb +80 -0
  81. data/spec/buildpack_support/component/versioned_dependency_component_spec.rb +58 -0
  82. data/spec/buildpack_support/component/versioned_downloads_spec.rb +58 -0
  83. data/spec/buildpack_support/component/with_timing_spec.rb +30 -0
  84. data/spec/buildpack_support/configuration_utils_spec.rb +39 -0
  85. data/spec/buildpack_support/constantize_spec.rb +34 -0
  86. data/spec/buildpack_support/dash_case_spec.rb +41 -0
  87. data/spec/buildpack_support/directory_finder_spec.rb +41 -0
  88. data/spec/buildpack_support/filtering_pathname_spec.rb +443 -0
  89. data/spec/buildpack_support/format_duration_spec.rb +60 -0
  90. data/spec/buildpack_support/logging/delegating_logger_spec.rb +62 -0
  91. data/spec/buildpack_support/logging/logger_factory_spec.rb +262 -0
  92. data/spec/buildpack_support/qualify_path_spec.rb +42 -0
  93. data/spec/buildpack_support/rake/buildpack_stage_task_spec.rb +88 -0
  94. data/spec/buildpack_support/rake/cached_artifact_finder_spec.rb +73 -0
  95. data/spec/buildpack_support/rake/check_api_doc_task_spec.rb +69 -0
  96. data/spec/buildpack_support/rake/dependency_cache_task_spec.rb +133 -0
  97. data/spec/buildpack_support/rake/disable_remote_downloads_task_spec.rb +91 -0
  98. data/spec/buildpack_support/rake/package_task_spec.rb +335 -0
  99. data/spec/buildpack_support/rake/package_zip_task_spec.rb +91 -0
  100. data/spec/buildpack_support/rake/repository_configuration_finder_spec.rb +61 -0
  101. data/spec/buildpack_support/rake/write_version_file_task_spec.rb +96 -0
  102. data/spec/buildpack_support/repository/configured_item_spec.rb +78 -0
  103. data/spec/buildpack_support/repository/repository_index_spec.rb +118 -0
  104. data/spec/buildpack_support/repository/wildcard_version_resolver_spec.rb +73 -0
  105. data/spec/buildpack_support/shell_spec.rb +32 -0
  106. data/spec/buildpack_support/snake_case_spec.rb +45 -0
  107. data/spec/buildpack_support/space_case_spec.rb +41 -0
  108. data/spec/buildpack_support/to_b_spec.rb +41 -0
  109. data/spec/buildpack_support/tokenized_version_spec.rb +132 -0
  110. data/spec/fixtures/application/test-file +0 -0
  111. data/spec/fixtures/config/found-config.yml +2 -0
  112. data/spec/fixtures/droplet-resources/droplet-resource +0 -0
  113. data/spec/fixtures/stub-download-with-top-level.zip +0 -0
  114. data/spec/fixtures/stub-download.tar.gz +0 -0
  115. data/spec/fixtures/stub-download.zip +0 -0
  116. data/spec/fixtures/test-cache.yml +18 -0
  117. data/spec/fixtures/test-index.yml +2 -0
  118. data/spec/fixtures/test_component.rb +0 -0
  119. data/spec/fixtures/zip-contents/test-directory/test-deep-file +0 -0
  120. data/spec/fixtures/zip-contents/test-file +0 -0
  121. data/spec/spec_helper.rb +30 -0
  122. metadata +416 -0
@@ -0,0 +1,40 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support/component'
17
+
18
+ module BuildpackSupport
19
+ module Component
20
+
21
+ # A mixin for printing out a caption and timing when executing a block
22
+ module WithTiming
23
+
24
+ # Wrap the execution of a block with timing information
25
+ #
26
+ # @param [String] caption the caption to print when timing starts
27
+ # @return [Void]
28
+ def with_timing(caption)
29
+ start_time = Time.now
30
+ print " #{caption} "
31
+
32
+ yield
33
+
34
+ puts "(#{(Time.now - start_time).duration})"
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support'
17
+ require 'buildpack_support/directory_finder'
18
+ require 'buildpack_support/logging/logger_factory'
19
+ require 'pathname'
20
+ require 'yaml'
21
+
22
+ module BuildpackSupport
23
+
24
+ # Utilities for dealing with Configuration files
25
+ class ConfigurationUtils
26
+ include DirectoryFinder
27
+
28
+ # Creates a new instance
29
+ #
30
+ # @param [Boolean] should_log whether the contents of the configuration file should be logged. This value should be
31
+ # left to its default and exists to allow the logger to use the utility.
32
+ def initialize(should_log = true)
33
+ @config_directory = load_path_peer 'config'
34
+ @logger = BuildpackSupport::Logging::LoggerFactory.instance.get_logger ConfigurationUtils if should_log
35
+ end
36
+
37
+ # Loads a configuration file from the buildpack configuration directory. If the configuration file does not exist,
38
+ # returns an empty hash.
39
+ #
40
+ # @param [String] identifier the identifier of the configuration
41
+ # @return [Hash] the configuration or an empty hash if the configuration file does not exist
42
+ def load(identifier)
43
+ file = @config_directory + "#{identifier}.yml"
44
+
45
+ configuration = {}
46
+ if file.exist?
47
+ configuration = YAML.load_file(file)
48
+ @logger.debug { "Configuration from #{file}: #{configuration}" } if @logger
49
+ else
50
+ @logger.debug { "No configuration file #{file} found" } if @logger
51
+ end
52
+
53
+ configuration
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,46 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # A mixin that adds the ability to turn a +String+ into a constant.
17
+ class String
18
+
19
+ # Tries to find a constant with the name specified by this +String+:
20
+ #
21
+ # "Module".constantize # => Module
22
+ # "Test::Unit".constantize # => Test::Unit
23
+ #
24
+ # The name is assumed to be the one of a top-level constant, no matter whether
25
+ # it starts with "::" or not. No lexical context is taken into account:
26
+ #
27
+ # C = 'outside'
28
+ # module M
29
+ # C = 'inside'
30
+ # C # => 'inside'
31
+ # "C".constantize # => 'outside', same as ::C
32
+ # end
33
+ #
34
+ # @return [String] The constantized rendering of this +String+.
35
+ # @raise NameError if the name is not in CamelCase or the constant is unknown.
36
+ def constantize
37
+ names = split('::')
38
+ names.shift if names.empty? || names.first.empty?
39
+
40
+ constant = Object
41
+ names.each do |name|
42
+ constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
43
+ end
44
+ constant
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # A mixin that adds the ability to turn a +String+ into dash case
17
+ class String
18
+
19
+ # Converts a string to dash case. For example, the String +Foo::DashCase+ would become +dash-case+.
20
+ #
21
+ # @return [String] The dash case rendering of this +String+
22
+ def dash_case
23
+ split('::').last
24
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2')
25
+ .gsub(/([a-z\d])([A-Z])/, '\1-\2')
26
+ .downcase
27
+ end
28
+
29
+ end
@@ -0,0 +1,45 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support'
17
+ require 'pathname'
18
+
19
+ module BuildpackSupport
20
+
21
+ # A module encapsulating all of the code for the directory finding utilities
22
+ module DirectoryFinder
23
+
24
+ # Finds a directory that is a peer of the +$LOAD_PATH+
25
+ #
26
+ # @param [String] name the name of the peer directory
27
+ # @return [Pathname] the path to the found directory if it exists, otherwise a path to the current working directory
28
+ def load_path_peer(name)
29
+ directory = Pathname.new('.nil')
30
+
31
+ $LOAD_PATH.each do |path|
32
+ candidate = Pathname.new(path) + '..' + name
33
+
34
+ next unless candidate.exist?
35
+
36
+ directory = candidate
37
+ break
38
+ end
39
+
40
+ directory
41
+ end
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,227 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support'
17
+ require 'pathname'
18
+ require 'set'
19
+
20
+ module BuildpackSupport
21
+
22
+ # This class conforms to the interface of +Pathname+, but filters the set of files that can be accessed and does not
23
+ # support +Pathname+'s class methods. This class also provides a +glob+ instance method which filters its output.
24
+ #
25
+ # If a +Pathname+ method which mutates the file system is called, it will throw an exception unless the instance is
26
+ # created as mutable.
27
+ #
28
+ # If the underlying filesystem is modified once an instance of this path has been created, the view provided
29
+ # by the instance will not change unless a file or directory allowed by the instance's filter is created, modified, or
30
+ # deleted.
31
+ class FilteringPathname
32
+
33
+ # Create a +FilteringPathname+ which behaves like the given pathname, but which applies the given filter to all files.
34
+ #
35
+ # The filesystem underpinning the given pathname must not contain a file or directory whose name is the name of the
36
+ # given pathname with '.nil' appended to it. This must be true for the lifetime of the +FilteringPathname+.
37
+ #
38
+ # The filter is applied to files which are accessed via the given pathname.
39
+ # If the filter returns +true+ for a particular pathname, the pathname behaves normally for this instance.
40
+ # If the filter returns +false+ for a particular pathname, the pathname behaves as if it does not exist.
41
+ #
42
+ # Note that the filter must obey the following rule: if the filter accepts Pathnames p and r, where p is a parent
43
+ # directory of r, then the filter must accept every Pathname q where p is a parent directory of q and q is a parent
44
+ # directory of r. FilteringPathname does not check that the filter obeys this rule.
45
+ #
46
+ # The +FilteringPathname+ may be immutable in which case calling a mutator method causes an exception to be thrown.
47
+ # Alternatively, the +FilteringPathname+ may be mutable in which case calling a mutator method may mutate the
48
+ # file system. The results of mutating the file system will be subject to filtering by the given filter.
49
+ #
50
+ # @param [Pathname] pathname the +Pathname+ which is to be filtered
51
+ # @param [Proc] filter a lambda which takes a +Pathname+ and returns either +true+ (to 'keep' the pathname) or
52
+ # +false+ (to filter out the pathname). Defaults to keeping everything
53
+ # @param [Boolean] mutable +true+ if and only if the +FilteringPathname+ may be used to mutate the file system
54
+ def initialize(pathname, filter, mutable)
55
+ fail 'Non-absolute pathname' unless pathname.absolute?
56
+
57
+ @pathname = pathname
58
+ @filter = filter
59
+ @mutable = mutable
60
+
61
+ @non_existent = Pathname.new "#{pathname}.nil"
62
+ check_file_does_not_exist @non_existent
63
+
64
+ @delegated_pathname = filter(@pathname) ? @pathname : @non_existent
65
+ end
66
+
67
+ # @see Pathname.
68
+ def <=>(other)
69
+ @pathname <=> comparison_target(other)
70
+ end
71
+
72
+ # @see Pathname.
73
+ def ==(other)
74
+ @pathname == comparison_target(other)
75
+ end
76
+
77
+ # @see Pathname.
78
+ def ===(other)
79
+ @pathname === comparison_target(other) # rubocop:disable CaseEquality
80
+ end
81
+
82
+ # Dispatch superclass methods via method_missing.
83
+ undef_method :taint
84
+ undef_method :untaint
85
+
86
+ # @see Pathname.
87
+ def +(other)
88
+ filtered_pathname(@pathname + other)
89
+ end
90
+
91
+ # @see Pathname.
92
+ def each_entry(&block)
93
+ delegate_and_yield_visible(:each_entry, &block)
94
+ end
95
+
96
+ # @see Pathname.
97
+ def entries
98
+ visible delegate.entries
99
+ end
100
+
101
+ # @see Pathname.
102
+ def open(mode = nil, *args, &block)
103
+ check_mutable if mode =~ /[wa]/
104
+ delegate.open(mode, *args, &block)
105
+ end
106
+
107
+ # @see Pathname.
108
+ def to_s
109
+ @pathname.to_s
110
+ end
111
+
112
+ # @see Pathname.
113
+ def children(with_directory = true)
114
+ if with_directory
115
+ super # delegate to method_missing
116
+ else
117
+ visible delegate.children(false)
118
+ end
119
+ end
120
+
121
+ # @see Pathname.
122
+ def each_child(with_directory = true, &block)
123
+ if with_directory
124
+ super # delegate to method_missing
125
+ else
126
+ delegate_and_yield_visible(:each_child, false, &block)
127
+ end
128
+ end
129
+
130
+ # Execute this +FilteringPathname+ as a glob.
131
+ def glob(flags = 0)
132
+ if block_given?
133
+ Pathname.glob(@pathname, flags) do |file|
134
+ yield filtered_pathname(file) if visible file
135
+ end
136
+ else
137
+ result = Pathname.glob(@pathname, flags)
138
+ convert_result_if_necessary(result)
139
+ end
140
+ end
141
+
142
+ attr_reader :pathname
143
+
144
+ protected :pathname
145
+
146
+ private
147
+
148
+ MUTATORS = [:chmod, :chown, :delete, :lchmod, :lchown, :make_link, :make_symlink, :mkdir, :mkpath, :rename, :rmdir, :rmtree, :taint, :unlink, :untaint].to_set.freeze
149
+
150
+ private_constant :MUTATORS
151
+
152
+ def check_file_does_not_exist(file)
153
+ fail "#{file} should not exist" if file.exist?
154
+ end
155
+
156
+ def check_mutable
157
+ fail 'FilteringPathname is immutable' unless @mutable
158
+ end
159
+
160
+ def comparison_target(other)
161
+ other.instance_of?(FilteringPathname) ? other.pathname : other
162
+ end
163
+
164
+ def convert_if_necessary(r)
165
+ if r.instance_of?(Pathname) && r.absolute?
166
+ filter(r) ? filtered_pathname(r) : nil
167
+ else
168
+ r
169
+ end
170
+ end
171
+
172
+ def convert_result_if_necessary(result)
173
+ if result.instance_of? Array
174
+ result.map { |r| convert_if_necessary(r) }.compact
175
+ else
176
+ result ? convert_if_necessary(result) || filtered_pathname(@non_existent) : nil
177
+ end
178
+ end
179
+
180
+ def delegate
181
+ check_file_does_not_exist @non_existent
182
+ @delegated_pathname
183
+ end
184
+
185
+ def delegate_and_yield_visible(method, *args)
186
+ delegate.send(method, *args) do |y|
187
+ yield y if visible y
188
+ end
189
+ end
190
+
191
+ def filtered_pathname(pathname)
192
+ FilteringPathname.new(pathname, @filter, @mutable)
193
+ end
194
+
195
+ def method_missing(method, *args)
196
+ check_mutable if MUTATORS.member? method
197
+ if block_given?
198
+ result = delegate.send(method, *args) do |*values|
199
+ converted_values = values.map { |value| convert_if_necessary(value) }.compact
200
+ yield(*converted_values) unless converted_values.empty?
201
+ end
202
+ else
203
+ result = delegate.send(method, *args)
204
+ end
205
+ convert_result_if_necessary(result)
206
+ end
207
+
208
+ def respond_to_missing?(symbol, include_private = false)
209
+ delegate.respond_to?(symbol, include_private)
210
+ end
211
+
212
+ def visible(entry)
213
+ if entry.instance_of? Array
214
+ entry.select { |child| visible(child) }
215
+ else
216
+ filter(@pathname + entry)
217
+ end
218
+ end
219
+
220
+ def filter(pathname)
221
+ fail 'Non-absolute pathname' unless pathname.absolute?
222
+ @filter.call(pathname.cleanpath)
223
+ end
224
+
225
+ end
226
+
227
+ end