buildpack-support 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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